-
Notifications
You must be signed in to change notification settings - Fork 8.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FABGW-25 Build ChaincodeInterest in TX simulator #2767
Conversation
@@ -21,13 +23,14 @@ type txSimulator struct { | |||
pvtdataQueriesPerformed bool | |||
simulationResultsComputed bool | |||
paginatedQueriesPerformed bool | |||
keySignaturePolicies map[string][]byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cannot this be simply a map[string]struct{}. Where key of the map entry will be the policy itself.
Otherwise, this will be a map[string]map[string][]byte to store <ns,key> as an entry. Moreover, you would need to add this details in the functions for pvt data as well - i.e., SetPrivateData
and SetPrivateDataMetadata
. So, holistically, this would need to store <ns,coll,key> as an entry.
simResults.PrivateReads = s.privateReads.Clone() | ||
for _, policy := range s.keySignaturePolicies { | ||
simResults.KeySignaturePolicies = append(simResults.KeySignaturePolicies, policy) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this cloning of both required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I've put a comment in the code explaining. There is an existing unit test that catches this.
core/ledger/ledger_interface.go
Outdated
} | ||
|
||
// Read returns whether a private data collection has been read during TX simulation. | ||
func (pr PrivateReads) Read(ns, coll string) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exists
may be a more meaningful name.
core/ledger/ledger_interface.go
Outdated
@@ -470,10 +470,42 @@ func (filter PvtNsCollFilter) Has(ns string, coll string) bool { | |||
return collFilter[coll] | |||
} | |||
|
|||
// PrivateReads captures which private data collections are read during TX simulation. | |||
type PrivateReads map[string]map[string]bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal but better to use canonical type map[string]map[string]struct{}
for a set.
core/endorser/endorser.go
Outdated
ccInterest.Chaincodes = append(ccInterest.Chaincodes, &pb.ChaincodeCall{ | ||
Name: prws.GetNamespace(), | ||
CollectionNames: []string{cprws.GetCollectionName()}, | ||
NoPrivateReads: !simResult.PrivateReads.Read(prws.Namespace, cprws.CollectionName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a clarification question - so multiple entries for a single chaincode are expected - one for each collection? I figured that though there a slice for specifying multiple collection names but only single flag for NoPrivateReads
- so is this a workaround to overcome that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly. I've added a comment in the code to this effect
core/endorser/endorser.go
Outdated
if nsrws.GetNamespace() == "_lifecycle" { | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At other places we avoided this hardcoding via this function. see if you could use this here easily. Otherwise, can introduce a function in that package that returns these names - which would cover the name for legacy lifecycle name as well (i.e., lscc
).
for _, policyBytes := range simResult.KeySignaturePolicies { | ||
policy, err := protoutil.UnmarshalSignaturePolicy(policyBytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
ccInterest.Chaincodes[0].KeyPolicies = append(ccInterest.Chaincodes[0].KeyPolicies, policy) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it won't make any difference functionally but just to confirm that you deliberately mention all the SBE in the first entry for the chaincode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in reality it makes no difference where they are
ec33bc8
to
7dceb7e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments
if versionedValue, err = s.txmgr.db.GetPrivateDataHash(ns, coll, key); err != nil { | ||
return err | ||
} | ||
_, metadata, _ = decomposeVersionedValue(versionedValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if versionedValue, err = s.txmgr.db.GetPrivateDataHash(ns, coll, key); err != nil { | |
return err | |
} | |
_, metadata, _ = decomposeVersionedValue(versionedValue) | |
s.txmgr.db.GetPrivateDataMetadataByHash(ns, coll, util.ComputeStringHash(key)) |
like GetStateMetadata
in the case of public key, GetPrivateDataMetadataByHash
applies an optimization that internally skips looking up for the keys for a chaincode that never used SBE
return s.policyFromMetadata(metadata) | ||
} | ||
|
||
func (s *txSimulator) policyFromMetadata(metadata []byte) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The current function name gives a feel as if this function just does the transformation and returns the policy. As this function actually makes a side-effect on state, can we call it addToKeySignaturePolicies
(or something of this effect)
} | ||
|
||
// If this private collection key has a SBE policy, add that policy to the set | ||
func (s *txSimulator) checkPrivateKeySignaturePolicy(ns string, coll string, key string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed invoking this function from functions SetPrivateData
and SetPrivateDataMetadata
? Likely you missed covering this in test as well.
core/endorser/endorser.go
Outdated
for _, prws := range simResult.PvtSimulationResults.GetNsPvtRwset() { | ||
for _, cprws := range prws.GetCollectionPvtRwset() { | ||
// Since each collection in a chaincode could have different values of the NoPrivateReads flag, create a new Chaincode entry for each. | ||
ccInterest.Chaincodes = append(ccInterest.Chaincodes, &pb.ChaincodeCall{ | ||
Name: prws.GetNamespace(), | ||
CollectionNames: []string{cprws.GetCollectionName()}, | ||
NoPrivateReads: !simResult.PrivateReads.Exists(prws.Namespace, cprws.CollectionName), | ||
}) | ||
chaincodes[prws.GetNamespace()] = struct{}{} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed noticing in this block earlier
- Even in the private read-write, we should skip the _lifecycle namespace (can skip IsSysCC(nsrws.GetNamespace())) -- As the client would specifically target the orgs for these transactions.
- This logic assumes that if a collection is read from, it is written to as well. So, the collections that are only present in the
PrivateReads
and not in the pvt-write-set will get a miss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. This logic was left over from my prototype which was building a full private read set, so this assumption would have held. I've now rewritten this entirely in a (hopefully) clearer way. And added an extra test case for this situation.
2789e5c
to
1f417db
Compare
1f417db
to
b381832
Compare
During transaction simulation, capture extra information to build a ChaincodeInterest structure specific to the chaincode invocation as follows: - Which private data collections are read from. - The SBE policies associated with any states that a written to. Following simulations, the ChaincodeInterest structure is built and returned in the ProposalResponse message. Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
b381832
to
4d34579
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Just left a pretty minor comment. I am fine merging this as is and you can fix the comments in a separate PR.
|
||
// 3. Add/merge collections from the PrivateReads struct | ||
for ns, entry := range simResult.PrivateReads { | ||
if cc := chaincodes[ns]; cc == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Skip systems chaincode in this block as well
- Add a test that asserts that the system chaincodes are indeed skipped
This commit addresses the closing comments in PR hyperledger#2767: - Skip systems chaincode in this block as well - Add a test that asserts that the system chaincodes are indeed skipped Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
This commit addresses the closing comments in PR #2767: - Skip systems chaincode in this block as well - Add a test that asserts that the system chaincodes are indeed skipped Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>
During transaction simulation, capture extra information to build a ChaincodeInterest structure specific to the chaincode invocation as follows:
Following simulations, the ChaincodeInterest structure is built and returned in the ProposalResponse message.
Signed-off-by: andrew-coleman andrew_coleman@uk.ibm.com