Skip to content

Commit

Permalink
Extend _lifecycle functions on checkcommitreadiness to provide detail…
Browse files Browse the repository at this point in the history
…s of the discrepancies

This patch updates some _lifecycle functions on checkcommitreadiness to
provide details of the discrepancies.

Signed-off-by: Tatsuya Sato <tatsuya.sato.so@hitachi.com>
  • Loading branch information
satota2 authored and denyeart committed Oct 9, 2023
1 parent e264d7d commit d5b6c10
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 125 deletions.
2 changes: 1 addition & 1 deletion core/chaincode/lifecycle/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ func (c *Cache) update(initializing bool, channelID string, dirtyChaincodes map[
channelCache.InterestingHashes[hash] = name
}

ok, err = c.Resources.Serializer.IsSerialized(NamespacesName, privateName, chaincodeDefinition.Parameters(), orgState)
ok, _, err = c.Resources.Serializer.IsSerialized(NamespacesName, privateName, chaincodeDefinition.Parameters(), orgState)

if err != nil {
return errors.WithMessagef(err, "could not check opaque org state for '%s' on channel '%s'", name, channelID)
Expand Down
44 changes: 26 additions & 18 deletions core/chaincode/lifecycle/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func (r *Resources) LifecycleEndorsementPolicyAsBytes(channelID string) ([]byte,
}

// ExternalFunctions is intended primarily to support the SCC functions.
// In general, its methods signatures produce writes (which must be commmitted
// In general, its methods signatures produce writes (which must be committed
// as part of an endorsement flow), or return human readable errors (for
// instance indicating a chaincode is not found) rather than sentinels.
// Instead, use the utility functions attached to the lifecycle Resources
Expand All @@ -316,28 +316,31 @@ type ExternalFunctions struct {
// CheckCommitReadiness takes a chaincode definition, checks that
// its sequence number is the next allowable sequence number and checks which
// organizations have approved the definition.
func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (approvals map[string]bool, mismatches map[string][]string, err error) {
var currentSequence int64
currentSequence, err = ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
if err != nil {
return nil, errors.WithMessage(err, "could not get current sequence")
err = errors.WithMessage(err, "could not get current sequence")
return
}

if cd.Sequence != currentSequence+1 {
return nil, errors.Errorf("requested sequence is %d, but new definition must be sequence %d", cd.Sequence, currentSequence+1)
err = errors.Errorf("requested sequence is %d, but new definition must be sequence %d", cd.Sequence, currentSequence+1)
return
}

if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
return nil, errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
if err = ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
err = errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
return
}

var approvals map[string]bool
if approvals, err = ef.QueryOrgApprovals(ccname, cd, orgStates); err != nil {
return nil, err
if approvals, mismatches, err = ef.QueryOrgApprovals(ccname, cd, orgStates); err != nil {
return
}

logger.Infof("Successfully checked commit readiness of chaincode name '%s' on channel '%s' with definition {%s}", ccname, chname, cd)

return approvals, nil
return
}

// CommitChaincodeDefinition takes a chaincode definition, checks that its
Expand All @@ -347,7 +350,7 @@ func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *Cha
// the approvals to determine if the result is valid (typically, this means
// checking that the peer's own org has approved the definition).
func (ef *ExternalFunctions) CommitChaincodeDefinition(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
approvals, err := ef.CheckCommitReadiness(chname, ccname, cd, publicState, orgStates)
approvals, _, err := ef.CheckCommitReadiness(chname, ccname, cd, publicState, orgStates)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -457,7 +460,7 @@ func (ef *ExternalFunctions) ApproveChaincodeDefinitionForOrg(chname, ccname str
}
// it might be the case that some organization just installed
// the chaincode and now would like to approve, therefore we
// need to check to distiguish the case. hence need to read from
// need to check to distinguish the case. hence need to read from
// the orgState metadata and see whenever this is the case
redefine, err := ef.isAttemptToRedefine(privateName, packageID, requestedSequence, cd, orgState)
if err != nil {
Expand Down Expand Up @@ -665,20 +668,25 @@ func (ef *ExternalFunctions) QueryChaincodeDefinition(name string, publicState R
// QueryOrgApprovals returns a map containing the orgs whose orgStates were
// provided and whether or not they have approved a chaincode definition with
// the specified parameters.
func (ef *ExternalFunctions) QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (map[string]bool, error) {
approvals := map[string]bool{}
func (ef *ExternalFunctions) QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (approvals map[string]bool, mismatches map[string][]string, err error) {
approvals = map[string]bool{}
mismatches = map[string][]string{}
privateName := fmt.Sprintf("%s#%d", name, cd.Sequence)
for _, orgState := range orgStates {
match, err := ef.Resources.Serializer.IsSerialized(NamespacesName, privateName, cd.Parameters(), orgState)
match, mismatchItems, err := ef.Resources.Serializer.IsSerialized(NamespacesName, privateName, cd.Parameters(), orgState)
if err != nil {
return nil, errors.WithMessagef(err, "serialization check failed for key %s", privateName)
return nil, nil, errors.WithMessagef(err, "serialization check failed for key %s", privateName)
}

_, org := implicitcollection.MspIDIfImplicitCollection(orgState.CollectionName())
logger.Infof("org %s's mismatch items are %v", org, mismatchItems)
approvals[org] = match
if len(mismatchItems) > 0 {
mismatches[org] = mismatchItems
}
}

return approvals, nil
return
}

// InstallChaincode installs a given chaincode to the peer's chaincode store.
Expand Down
25 changes: 16 additions & 9 deletions core/chaincode/lifecycle/lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1022,12 +1022,16 @@ var _ = Describe("ExternalFunctions", func() {
})

It("checks the commit readiness of a chaincode definition and returns the approvals", func() {
approvals, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
approvals, mismatches, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).NotTo(HaveOccurred())
Expect(approvals).To(Equal(map[string]bool{
"org0": true,
"org1": false,
}))
Expect(mismatches).
To(Equal(map[string][]string{
"org1": {"EndorsementInfo", "ValidationInfo"},
}))
})

Context("when IsSerialized fails", func() {
Expand All @@ -1036,7 +1040,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("wraps and returns an error", func() {
_, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
_, _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError(ContainSubstring("serialization check failed for key cc-name#5: could not get value for key namespaces/metadata/cc-name#5: bad bad failure")))
})
})
Expand All @@ -1062,12 +1066,15 @@ var _ = Describe("ExternalFunctions", func() {
})

It("applies the chaincode definition and returns the approvals", func() {
approvals, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
approvals, mismatches, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).NotTo(HaveOccurred())
Expect(approvals).To(Equal(map[string]bool{
"org0": true,
"org1": false,
}))
Expect(mismatches).To(Equal(map[string][]string{
"org1": {"EndorsementInfo", "ValidationInfo"},
}))
})

Context("when no default endorsement policy is defined on the channel", func() {
Expand All @@ -1076,7 +1083,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("returns an error", func() {
_, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
_, _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError(ContainSubstring("could not set defaults for chaincode definition in " +
"channel my-channel: policy '/Channel/Application/Endorsement' must be defined " +
"for channel 'my-channel' before chaincode operations can be attempted")))
Expand All @@ -1089,7 +1096,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("returns an error", func() {
_, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
_, _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError(ContainSubstring("could not get channel config for channel 'my-channel'")))
})
})
Expand All @@ -1100,7 +1107,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("wraps and returns the error", func() {
_, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
_, _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError("could not get current sequence: could not get state for key namespaces/fields/cc-name/Sequence: getstate-error"))
})
})
Expand All @@ -1121,7 +1128,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("returns an error", func() {
_, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
_, _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError("requested sequence is 5, but new definition must be sequence 4"))
})
})
Expand Down Expand Up @@ -1767,7 +1774,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("returns the org approvals", func() {
approvals, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
approvals, _, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).NotTo(HaveOccurred())
Expect(approvals).To(Equal(map[string]bool{
"org0": true,
Expand All @@ -1781,7 +1788,7 @@ var _ = Describe("ExternalFunctions", func() {
})

It("wraps and returns an error", func() {
approvals, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
approvals, _, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]})
Expect(err).To(MatchError("serialization check failed for key cc-name#4: could not get value for key namespaces/metadata/cc-name#4: owww that hurt"))
Expect(approvals).To(BeNil())
})
Expand Down
Loading

0 comments on commit d5b6c10

Please sign in to comment.