Skip to content
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

Merged
merged 1 commit into from
Jul 21, 2021

Conversation

andrew-coleman
Copy link
Member

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

@andrew-coleman andrew-coleman requested a review from a team as a code owner July 20, 2021 11:07
@andrew-coleman andrew-coleman marked this pull request as draft July 20, 2021 11:07
@andrew-coleman andrew-coleman marked this pull request as ready for review July 20, 2021 12:19
core/ledger/kvledger/txmgmt/txmgr/query_executor.go Outdated Show resolved Hide resolved
core/ledger/kvledger/txmgmt/txmgr/query_executor.go Outdated Show resolved Hide resolved
core/ledger/kvledger/txmgmt/txmgr/query_executor.go Outdated Show resolved Hide resolved
@@ -21,13 +23,14 @@ type txSimulator struct {
pvtdataQueriesPerformed bool
simulationResultsComputed bool
paginatedQueriesPerformed bool
keySignaturePolicies map[string][]byte
Copy link
Contributor

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.

Comment on lines 186 to 205
simResults.PrivateReads = s.privateReads.Clone()
for _, policy := range s.keySignaturePolicies {
simResults.KeySignaturePolicies = append(simResults.KeySignaturePolicies, policy)
}
Copy link
Contributor

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?

Copy link
Member Author

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.

}

// Read returns whether a private data collection has been read during TX simulation.
func (pr PrivateReads) Read(ns, coll string) bool {
Copy link
Contributor

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.

@@ -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
Copy link
Contributor

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.

Comment on lines 521 to 524
ccInterest.Chaincodes = append(ccInterest.Chaincodes, &pb.ChaincodeCall{
Name: prws.GetNamespace(),
CollectionNames: []string{cprws.GetCollectionName()},
NoPrivateReads: !simResult.PrivateReads.Read(prws.Namespace, cprws.CollectionName),
Copy link
Contributor

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?

Copy link
Member Author

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

Comment on lines 533 to 495
if nsrws.GetNamespace() == "_lifecycle" {
continue
Copy link
Contributor

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).

Comment on lines +545 to +548
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)
}
Copy link
Contributor

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?

Copy link
Member Author

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

@andrew-coleman andrew-coleman force-pushed the build_interest branch 2 times, most recently from ec33bc8 to 7dceb7e Compare July 20, 2021 17:06
Copy link
Contributor

@manish-sethi manish-sethi left a 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

Comment on lines 62 to 65
if versionedValue, err = s.txmgr.db.GetPrivateDataHash(ns, coll, key); err != nil {
return err
}
_, metadata, _ = decomposeVersionedValue(versionedValue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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 {
Copy link
Contributor

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 {
Copy link
Contributor

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.

Comment on lines 479 to 506
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{}{}
}
}
}
Copy link
Contributor

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.

Copy link
Member Author

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.

@andrew-coleman andrew-coleman force-pushed the build_interest branch 2 times, most recently from 2789e5c to 1f417db Compare July 21, 2021 11:07
@andrew-coleman andrew-coleman marked this pull request as draft July 21, 2021 11:22
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>
@andrew-coleman andrew-coleman marked this pull request as ready for review July 21, 2021 12:31
Copy link
Contributor

@manish-sethi manish-sethi left a 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 {
Copy link
Contributor

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

@manish-sethi manish-sethi merged commit 26ec54a into hyperledger:main Jul 21, 2021
@andrew-coleman andrew-coleman deleted the build_interest branch July 21, 2021 14:52
andrew-coleman added a commit to andrew-coleman/fabric that referenced this pull request Jul 22, 2021
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>
manish-sethi pushed a commit that referenced this pull request Jul 22, 2021
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants