Skip to content

Commit

Permalink
Merge "[FAB-15066] Enable endorsement policies for collections"
Browse files Browse the repository at this point in the history
  • Loading branch information
manish-sethi authored and Gerrit Code Review committed Nov 20, 2019
2 parents 1946812 + b852a86 commit 60ef90d
Show file tree
Hide file tree
Showing 7 changed files with 384 additions and 31 deletions.
22 changes: 12 additions & 10 deletions core/chaincode/lifecycle/deployedcc_infoprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
"github.com/hyperledger/fabric-protos-go/msp"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/util"
validationState "github.com/hyperledger/fabric/core/handlers/validation/api/state"
Expand All @@ -35,8 +34,8 @@ const (

var (
// This is a channel which was created with a lifecycle endorsement policy
LifecycleDefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{
LifecycleDefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
ChannelConfigPolicyReference: LifecycleEndorsementPolicyRef,
},
})
Expand Down Expand Up @@ -248,8 +247,8 @@ func (vc *ValidatorCommitter) ImplicitCollectionEndorsementPolicyAsBytes(channel

policyName := fmt.Sprintf("/Channel/Application/%s/Endorsement", matchedOrgName)
if _, ok := channelConfig.PolicyManager().GetPolicy(policyName); ok {
return protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{
ChannelConfigPolicyReference: policyName,
},
}), nil, nil
Expand All @@ -258,8 +257,8 @@ func (vc *ValidatorCommitter) ImplicitCollectionEndorsementPolicyAsBytes(channel
// This was a channel which was upgraded or did not define an org level endorsement policy, use a default
// of "any member of the org"

return protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
Type: &pb.ApplicationPolicy_SignaturePolicy{
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_SignaturePolicy{
SignaturePolicy: cauthdsl.SignedByAnyMember([]string{orgMSPID}),
},
}), nil, nil
Expand Down Expand Up @@ -287,8 +286,8 @@ func (vc *ValidatorCommitter) LifecycleEndorsementPolicyAsBytes(channelID string
mspids = append(mspids, org.MSPID())
}

return protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
Type: &pb.ApplicationPolicy_SignaturePolicy{
return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_SignaturePolicy{
SignaturePolicy: cauthdsl.SignedByNOutOfGivenRole(int32(len(mspids)/2+1), msp.MSPRole_MEMBER, mspids),
},
}), nil
Expand Down Expand Up @@ -354,7 +353,10 @@ func (vc *ValidatorCommitter) CollectionValidationInfo(channelID, chaincodeName,
for _, conf := range definedChaincode.Collections.Config {
staticCollConfig := conf.GetStaticCollectionConfig()
if staticCollConfig != nil && staticCollConfig.Name == collectionName {
// TODO, return the collection EP if defined
if staticCollConfig.EndorsementPolicy != nil {
return protoutil.MarshalOrPanic(staticCollConfig.EndorsementPolicy), nil, nil
}
// default to chaincode endorsement policy
return definedChaincode.ValidationInfo.ValidationParameter, nil, nil
}
}
Expand Down
58 changes: 53 additions & 5 deletions core/chaincode/lifecycle/deployedcc_infoprovider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import (

cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric-protos-go/msp"
lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/lifecycle"
"github.com/hyperledger/fabric/core/chaincode/lifecycle/mock"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/protoutil"

"github.com/golang/protobuf/proto"

Expand Down Expand Up @@ -480,7 +481,7 @@ var _ = Describe("ValidatorCommitter", func() {
b, err := vc.LifecycleEndorsementPolicyAsBytes("channel-id")
Expect(err).NotTo(HaveOccurred())
Expect(b).NotTo(BeNil())
policy := &pb.ApplicationPolicy{}
policy := &cb.ApplicationPolicy{}
err = proto.Unmarshal(b, policy)
Expect(err).NotTo(HaveOccurred())
Expect(policy.GetChannelConfigPolicyReference()).To(Equal("/Channel/Application/LifecycleEndorsement"))
Expand All @@ -494,7 +495,7 @@ var _ = Describe("ValidatorCommitter", func() {
It("returns an error", func() {
b, err := vc.LifecycleEndorsementPolicyAsBytes("channel-id")
Expect(err).NotTo(HaveOccurred())
policy := &pb.ApplicationPolicy{}
policy := &cb.ApplicationPolicy{}
err = proto.Unmarshal(b, policy)
Expect(err).NotTo(HaveOccurred())
Expect(policy.GetSignaturePolicy()).NotTo(BeNil())
Expand Down Expand Up @@ -650,14 +651,61 @@ var _ = Describe("ValidatorCommitter", func() {
})
})
})

Context("when the endorsement policy is specified in the collection config", func() {
var expectedPolicy *cb.ApplicationPolicy

BeforeEach(func() {
expectedPolicy = &cb.ApplicationPolicy{
Type: &cb.ApplicationPolicy_SignaturePolicy{
SignaturePolicy: &cb.SignaturePolicyEnvelope{
Identities: []*msp.MSPPrincipal{
{
Principal: []byte("test"),
},
},
},
},
}
err := resources.Serializer.Serialize(lifecycle.NamespacesName, "cc-name", &lifecycle.ChaincodeDefinition{
EndorsementInfo: &lb.ChaincodeEndorsementInfo{
Version: "version",
},
ValidationInfo: &lb.ChaincodeValidationInfo{
ValidationPlugin: "validation-plugin",
ValidationParameter: []byte("validation-parameter"),
},
Collections: &cb.CollectionConfigPackage{
Config: []*cb.CollectionConfig{
{
Payload: &cb.CollectionConfig_StaticCollectionConfig{
StaticCollectionConfig: &cb.StaticCollectionConfig{
Name: "collection-name",
EndorsementPolicy: expectedPolicy,
},
},
},
},
},
}, fakePublicState)
Expect(err).NotTo(HaveOccurred())
})

It("returns the endorsement policy from the collection config", func() {
ep, uErr, vErr := vc.CollectionValidationInfo("channel-id", "cc-name", "collection-name", fakeValidationState)
Expect(uErr).NotTo(HaveOccurred())
Expect(vErr).NotTo(HaveOccurred())
Expect(ep).To(Equal(protoutil.MarshalOrPanic(expectedPolicy)))
})
})
})

Describe("ImplicitCollectionEndorsementPolicyAsBytes", func() {
It("returns the marshaled standard EP for an implicit collection", func() {
ep, uErr, vErr := vc.ImplicitCollectionEndorsementPolicyAsBytes("channel-id", "first-mspid")
Expect(uErr).NotTo(HaveOccurred())
Expect(vErr).NotTo(HaveOccurred())
policy := &pb.ApplicationPolicy{}
policy := &cb.ApplicationPolicy{}
err := proto.Unmarshal(ep, policy)
Expect(err).NotTo(HaveOccurred())
Expect(policy.GetChannelConfigPolicyReference()).To(Equal("/Channel/Application/org0/Endorsement"))
Expand All @@ -672,7 +720,7 @@ var _ = Describe("ValidatorCommitter", func() {
ep, uErr, vErr := vc.ImplicitCollectionEndorsementPolicyAsBytes("channel-id", "first-mspid")
Expect(uErr).NotTo(HaveOccurred())
Expect(vErr).NotTo(HaveOccurred())
policy := &pb.ApplicationPolicy{}
policy := &cb.ApplicationPolicy{}
err := proto.Unmarshal(ep, policy)
Expect(err).NotTo(HaveOccurred())
Expect(policy.GetSignaturePolicy()).NotTo(BeNil())
Expand Down
84 changes: 84 additions & 0 deletions integration/pvtdata/pvtdata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,90 @@ var _ bool = Describe("PrivateData", func() {
})
})
})

Describe("Collection Config Endorsement Policy", func() {
BeforeEach(func() {
testChaincode = chaincode{
Chaincode: newLifecycleChaincode,
isLegacy: false,
}
nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peers...)
})

When("a peer specified in the chaincode endorsement policy but not in the collection config endorsement policy is used to invoke the chaincode", func() {
It("fails validation", func() {
By("setting the collection config endorsement policy to org2 or org3 peers")
testChaincode.CollectionsConfig = collectionConfig("collections_config4.json")

By("deploying new lifecycle chaincode")
// set collection endorsement policy to org2 or org3
deployChaincode(network, orderer, testChaincode)

By("adding marble1 with an org1 peer as endorser")
peer := network.Peer("Org1", "peer0")
marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`
marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDetails))

command := commands.ChaincodeInvoke{
ChannelID: channelID,
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
Name: testChaincode.Name,
Ctor: fmt.Sprintf(`{"Args":["initMarble"]}`),
Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64),
PeerAddresses: []string{
network.PeerAddress(peer, nwo.ListenPort),
},
WaitForEvent: true,
}

sess, err := network.PeerUserSession(peer, "User1", command)
Expect(err).NotTo(HaveOccurred())
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
Expect(sess.Err).To(gbytes.Say("ENDORSEMENT_POLICY_FAILURE"))
})
})

When("a peer specified in the collection endorsement policy but not in the chaincode endorsement policy is used to invoke the chaincode", func() {
When("the collection endorsement policy is a signature policy", func() {
It("successfully invokes the chaincode", func() {
// collection config endorsement policy specifies org2 or org3 peers for endorsement
By("setting the collection config endorsement policy to use a signature policy")
testChaincode.CollectionsConfig = collectionConfig("collections_config4.json")

By("setting the chaincode endorsement policy to org1 or org2 peers")
testChaincode.SignaturePolicy = `OR ('Org1MSP.member','Org2MSP.member')`

By("deploying new lifecycle chaincode")
// set collection endorsement policy to org2 or org3
deployChaincode(network, orderer, testChaincode)

By("adding marble1 with an org3 peer as endorser")
peer := network.Peer("Org3", "peer0")
marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`
addMarble(network, orderer, testChaincode.Name, marbleDetails, peer)
})
})

When("the collection endorsement policy is a channel config policy reference", func() {
It("successfully invokes the chaincode", func() {
// collection config endorsement policy specifies channel config policy reference /Channel/Application/Readers
By("setting the collection config endorsement policy to use a channel config policy reference")
testChaincode.CollectionsConfig = collectionConfig("collections_config5.json")

By("setting the channel endorsement policy to org1 or org2 peers")
testChaincode.SignaturePolicy = `OR ('Org1MSP.member','Org2MSP.member')`

By("deploying new lifecycle chaincode")
deployChaincode(network, orderer, testChaincode)

By("adding marble1 with an org3 peer as endorser")
peer := network.Peer("Org3", "peer0")
marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`
addMarble(network, orderer, testChaincode.Name, marbleDetails, peer)
})
})
})
})
})
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"name": "collectionMarbles",
"policy": "OR('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 2,
"blockToLive":1000000,
"memberOnlyRead": false,
"endorsementPolicy": {
"signaturePolicy": "OR('Org2MSP.member', 'Org3MSP.member')"
}
},
{
"name": "collectionMarblePrivateDetails",
"policy": "OR('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 2,
"blockToLive":1000000,
"memberOnlyRead": false,
"endorsementPolicy": {
"signaturePolicy": "OR('Org2MSP.member', 'Org3MSP.member')"
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"name": "collectionMarbles",
"policy": "OR('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 2,
"blockToLive":1000000,
"memberOnlyRead": false,
"endorsementPolicy": {
"channelConfigPolicy": "/Channel/Application/Readers"
}
},
{
"name": "collectionMarblePrivateDetails",
"policy": "OR('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 2,
"blockToLive":1000000,
"memberOnlyRead": false,
"endorsementPolicy": {
"channelConfigPolicy": "/Channel/Application/Readers"
}
}
]
Loading

0 comments on commit 60ef90d

Please sign in to comment.