diff --git a/integration/pvtdata/pvtdata_test.go b/integration/pvtdata/pvtdata_test.go index 28951fa73ff..978905c4a6e 100644 --- a/integration/pvtdata/pvtdata_test.go +++ b/integration/pvtdata/pvtdata_test.go @@ -42,7 +42,6 @@ import ( "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" "github.com/tedsuo/ifrit" - yaml "gopkg.in/yaml.v2" ) // The chaincode used in these tests has two collections defined: @@ -50,464 +49,482 @@ import ( // when calling QueryChaincode with first arg "readMarble", it will query collectionMarbles // when calling QueryChaincode with first arg "readMarblePrivateDetails", it will query collectionMarblePrivateDetails +const channelID = "testchannel" + var _ bool = Describe("PrivateData", func() { var ( - testDir string - network *nwo.Network - process ifrit.Process - orderer *nwo.Orderer - allPeers []*nwo.Peer - - legacyChaincode nwo.Chaincode - newLifecycleChaincode nwo.Chaincode - testChaincode chaincode - helper *testHelper - ) + network *nwo.Network + process ifrit.Process - BeforeEach(func() { - testDir, network = initThreeOrgsSetup() - legacyChaincode = nwo.Chaincode{ - Name: "marblesp", - Version: "1.0", - Path: "github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd", - Ctor: `{"Args":["init"]}`, - Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, - // collections_config1.json defines the access as follows: - // 1. collectionMarbles - Org1, Org2 have access to this collection - // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection - CollectionsConfig: collectionConfig("collections_config1.json"), - } + orderer *nwo.Orderer + ) - newLifecycleChaincode = nwo.Chaincode{ - Name: "marblesp", - Version: "1.0", - Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd"), - Lang: "binary", - PackageFile: filepath.Join(testDir, "marbles-pvtdata.tar.gz"), - Label: "marbles-private-20", - SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, - CollectionsConfig: collectionConfig("collections_config1.json"), - Sequence: "1", - } + AfterEach(func() { + testCleanup(network, process) }) - JustBeforeEach(func() { - process, orderer, allPeers = startNetwork(network) - helper = &testHelper{ - networkHelper: &networkHelper{ - Network: network, - orderer: orderer, - peers: allPeers, - testDir: testDir, - channelID: "testchannel", - }, - } - }) + Describe("Dissemination when pulling is disabled", func() { + It("disseminates private data per collections_config1", func() { + By("setting up the network") + network = initThreeOrgsSetup() + + By("setting the pull retry threshold to 0 on all peers") + // set pull retry threshold to 0 + for _, p := range network.Peers { + core := network.ReadPeerConfig(p) + core.Peer.Gossip.PvtData.PullRetryThreshold = 0 + network.WritePeerConfig(p, core) + } - AfterEach(func() { - testCleanup(testDir, network, process) + By("starting the network") + process, orderer = startNetwork(network) + + By("deploying legacy chaincode and adding marble1") + testChaincode := chaincode{ + Chaincode: nwo.Chaincode{ + Name: "marblesp", + Version: "1.0", + Path: "github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd", + Ctor: `{"Args":["init"]}`, + Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, + // collections_config1.json defines the access as follows: + // 1. collectionMarbles - Org1, Org2 have access to this collection + // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection + CollectionsConfig: collectionConfig("collections_config1.json"), + }, + isLegacy: true, + } + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, + `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, + network.Peer("Org1", "peer0"), + ) + + assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1") + }) }) - Describe("Dissemination", func() { - When("pulling is disabled by setting the pull retry threshold to 0", func() { - BeforeEach(func() { - // set pull retry threshold to 0 - peers := []*nwo.Peer{ - network.Peer("org1", "peer0"), - network.Peer("org2", "peer0"), - network.Peer("org3", "peer0"), - } - for _, p := range peers { - core := network.ReadPeerConfig(p) - core.Peer.Gossip.PvtData.PullRetryThreshold = 0 - network.WritePeerConfig(p, core) - } - }) + Describe("Pvtdata behavior with untouched peer configs", func() { + var ( + legacyChaincode nwo.Chaincode + newLifecycleChaincode nwo.Chaincode + testChaincode chaincode + + org1Peer1, org2Peer1 *nwo.Peer + ) + + BeforeEach(func() { + By("setting up the network") + network = initThreeOrgsSetup() + legacyChaincode = nwo.Chaincode{ + Name: "marblesp", + Version: "1.0", + Path: "github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd", + Ctor: `{"Args":["init"]}`, + Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, + // collections_config1.json defines the access as follows: + // 1. collectionMarbles - Org1, Org2 have access to this collection + // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection + CollectionsConfig: collectionConfig("collections_config1.json"), + } + + newLifecycleChaincode = nwo.Chaincode{ + Name: "marblesp", + Version: "1.0", + Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd"), + Lang: "binary", + PackageFile: filepath.Join(network.RootDir, "marbles-pvtdata.tar.gz"), + Label: "marbles-private-20", + SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, + CollectionsConfig: collectionConfig("collections_config1.json"), + Sequence: "1", + } + org1Peer1 = &nwo.Peer{ + Name: "peer1", + Organization: "Org1", + Channels: []*nwo.PeerChannel{ + {Name: channelID}, + }, + } + org2Peer1 = &nwo.Peer{ + Name: "peer1", + Organization: "Org2", + Channels: []*nwo.PeerChannel{ + {Name: channelID}, + }, + } + + process, orderer = startNetwork(network) + }) - JustBeforeEach(func() { + Describe("Reconciliation and pulling", func() { + var newPeerProcess ifrit.Process + + BeforeEach(func() { By("deploying legacy chaincode and adding marble1") testChaincode = chaincode{ Chaincode: legacyChaincode, isLegacy: true, } - helper.deployChaincode(testChaincode) - helper.addMarble(testChaincode.Name, + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, - network.Peer("org1", "peer0"), + network.Peer("Org1", "peer0"), ) }) - It("disseminates private data per collections_config1", func() { - helper.assertPvtdataPresencePerCollectionConfig1(testChaincode.Name, "marble1") - }) - }) - - }) - - Describe("Reconciliation and pulling", func() { - JustBeforeEach(func() { - By("deploying legacy chaincode and adding marble1") - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, - } - helper.deployChaincode(testChaincode) - helper.addMarble(testChaincode.Name, - `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, - network.Peer("org1", "peer0"), - ) - }) - - assertReconcileBehavior := func() { - It("disseminates private data per collections_config1", func() { - helper.assertPvtdataPresencePerCollectionConfig1(testChaincode.Name, "marble1") + AfterEach(func() { + if newPeerProcess != nil { + newPeerProcess.Signal(syscall.SIGTERM) + Eventually(newPeerProcess.Wait(), network.EventuallyTimeout).Should(Receive()) + } }) - When("org3 is added to collectionMarbles via chaincode upgrade with collections_config2", func() { - JustBeforeEach(func() { - // collections_config2.json defines the access as follows: - // 1. collectionMarbles - Org1, Org2 and Org3 have access to this collection - // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection - // the change from collections_config1 - org3 was added to collectionMarbles - testChaincode.Version = "1.1" - testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") - if !testChaincode.isLegacy { - testChaincode.Sequence = "2" - } - helper.upgradeChaincode(testChaincode) + assertReconcileBehavior := func() { + It("disseminates private data per collections_config1", func() { + assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1") }) - It("distributes and allows access to newly added private data per collections_config2", func() { - helper.addMarble(testChaincode.Name, - `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, - network.Peer("org2", "peer0"), - ) - helper.assertPvtdataPresencePerCollectionConfig2(testChaincode.Name, "marble2") + When("org3 is added to collectionMarbles via chaincode upgrade with collections_config2", func() { + It("distributes and allows access to newly added private data per collections_config2", func() { + By("upgrading the chaincode and adding marble2") + // collections_config2.json defines the access as follows: + // 1. collectionMarbles - Org1, Org2 and Org3 have access to this collection + // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection + // the change from collections_config1 - org3 was added to collectionMarbles + testChaincode.Version = "1.1" + testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") + if !testChaincode.isLegacy { + testChaincode.Sequence = "2" + } + upgradeChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, + `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, + network.Peer("Org2", "peer0"), + ) + + assertPvtdataPresencePerCollectionConfig2(network, testChaincode.Name, "marble2") + }) }) - }) - When("a new peer in org1 joins the channel", func() { - var ( - newPeer *nwo.Peer - ) - JustBeforeEach(func() { - newPeer = network.Peer("org1", "peer1") - helper.addPeer(newPeer) - allPeers = append(allPeers, newPeer) - helper.installChaincode(testChaincode, newPeer) - network.VerifyMembership(allPeers, "testchannel", "marblesp") - }) + When("a new peer in org1 joins the channel", func() { + It("causes the new peer to pull the existing private data only for collectionMarbles", func() { + By("adding a new peer") + newPeerProcess = addPeer(network, orderer, org1Peer1) + installChaincode(network, testChaincode, org1Peer1) + network.VerifyMembership(network.Peers, channelID, "marblesp") - It("causes the new peer to pull the existing private data only for collectionMarbles", func() { - helper.assertPvtdataPresencePerCollectionConfig1(testChaincode.Name, "marble1", newPeer) + assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1", org1Peer1) + }) }) + } + + When("chaincode in legacy lifecycle", func() { + assertReconcileBehavior() }) - } - Context("chaincode in legacy lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, - } + When("chaincode is migrated from legacy to new lifecycle with same collection config", func() { + BeforeEach(func() { + testChaincode = chaincode{ + Chaincode: newLifecycleChaincode, + isLegacy: false, + } + nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) + upgradeChaincode(network, orderer, testChaincode) + }) + assertReconcileBehavior() }) - assertReconcileBehavior() }) - Context("chaincode is migrated from legacy to new lifecycle with same collection config", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: newLifecycleChaincode, - isLegacy: false, + Describe("BlockToLive", func() { + var newPeerProcess ifrit.Process + + AfterEach(func() { + if newPeerProcess != nil { + newPeerProcess.Signal(syscall.SIGTERM) + Eventually(newPeerProcess.Wait(), network.EventuallyTimeout).Should(Receive()) } - nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, allPeers...) - helper.upgradeChaincode(testChaincode) }) - assertReconcileBehavior() - }) - }) - Describe("BlockToLive", func() { - assertBlockToLiveBehavior := func() { - It("purges private data after BTL and causes new peer not to pull the purged private data", func() { - testChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") - eligiblePeer := network.Peer("org2", "peer0") + assertBlockToLiveBehavior := func() { + eligiblePeer := network.Peer("Org2", "peer0") ccName := testChaincode.Name - - By("deploying chaincode and adding marble1") - helper.deployChaincode(testChaincode) - helper.addMarble(ccName, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, eligiblePeer) - By("adding three blocks") for i := 0; i < 3; i++ { - helper.addMarble(ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) + addMarble(network, orderer, ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) } By("verifying that marble1 still not purged in collection MarblesPD") - helper.assertPresentInCollectionMPD(ccName, "marble1", eligiblePeer) + assertPresentInCollectionMPD(network, ccName, "marble1", eligiblePeer) By("adding one more block") - helper.addMarble(ccName, `{"name":"fun-marble-3", "color":"blue", "size":35, "owner":"tom", "price":99}`, eligiblePeer) + addMarble(network, orderer, ccName, `{"name":"fun-marble-3", "color":"blue", "size":35, "owner":"tom", "price":99}`, eligiblePeer) By("verifying that marble1 purged in collection MarblesPD") - helper.assertDoesNotExistInCollectionMPD(ccName, "marble1", eligiblePeer) + assertDoesNotExistInCollectionMPD(network, ccName, "marble1", eligiblePeer) By("verifying that marble1 still not purged in collection Marbles") - helper.assertPresentInCollectionM(ccName, "marble1", eligiblePeer) + assertPresentInCollectionM(network, ccName, "marble1", eligiblePeer) By("adding new peer that is eligible to recieve data") - newEligiblePeer := network.Peer("org2", "peer1") - helper.addPeer(newEligiblePeer) - allPeers = append(allPeers, newEligiblePeer) - helper.installChaincode(testChaincode, newEligiblePeer) - helper.VerifyMembership(allPeers, "testchannel", ccName) - helper.assertPresentInCollectionM(ccName, "marble1", newEligiblePeer) - helper.assertDoesNotExistInCollectionMPD(ccName, "marble1", newEligiblePeer) - }) - } + newPeerProcess = addPeer(network, orderer, org2Peer1) + installChaincode(network, testChaincode, org2Peer1) + network.VerifyMembership(network.Peers, channelID, ccName) + assertPresentInCollectionM(network, ccName, "marble1", org2Peer1) + assertDoesNotExistInCollectionMPD(network, ccName, "marble1", org2Peer1) + } - Context("chaincode in legacy lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, - } + When("chaincode in legacy lifecycle", func() { + It("purges private data after BTL and causes new peer not to pull the purged private data", func() { + By("deploying legacy chaincode and adding marble1") + testChaincode = chaincode{ + Chaincode: legacyChaincode, + isLegacy: true, + } + + testChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) + + assertBlockToLiveBehavior() + }) }) - assertBlockToLiveBehavior() - }) - Context("chaincode in new lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: newLifecycleChaincode, - isLegacy: false, - } - nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, allPeers...) + When("chaincode in new lifecycle", func() { + It("purges private data after BTL and causes new peer not to pull the purged private data", func() { + By("deploying new lifecycle chaincode and adding marble1") + testChaincode = chaincode{ + Chaincode: newLifecycleChaincode, + isLegacy: false, + } + nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) + + testChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) + + assertBlockToLiveBehavior() + }) }) - assertBlockToLiveBehavior() }) - }) - - Describe("Org removal from collection", func() { - assertOrgRemovalBehavior := func() { - It("causes removed org not to get new data", func() { - testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") - helper.deployChaincode(testChaincode) - helper.addMarble(testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("org2", "peer0")) - helper.assertPvtdataPresencePerCollectionConfig2(testChaincode.Name, "marble1") + Describe("Org removal from collection", func() { + assertOrgRemovalBehavior := func() { By("upgrading chaincode to remove org3 from collectionMarbles") testChaincode.CollectionsConfig = collectionConfig("collections_config1.json") testChaincode.Version = "1.1" if !testChaincode.isLegacy { testChaincode.Sequence = "2" } - helper.upgradeChaincode(testChaincode) - helper.addMarble(testChaincode.Name, `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, network.Peer("org2", "peer0")) - helper.assertPvtdataPresencePerCollectionConfig1(testChaincode.Name, "marble2") + upgradeChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, network.Peer("Org2", "peer0")) + assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble2") + } + + When("chaincode in legacy lifecycle", func() { + It("causes removed org not to get new data", func() { + By("deploying legacy chaincode and adding marble1") + testChaincode = chaincode{ + Chaincode: legacyChaincode, + isLegacy: true, + } + testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) + assertPvtdataPresencePerCollectionConfig2(network, testChaincode.Name, "marble1") + + assertOrgRemovalBehavior() + }) }) - } - Context("chaincode in legacy lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, - } + When("chaincode in new lifecycle", func() { + It("causes removed org not to get new data", func() { + By("deploying new lifecycle chaincode and adding marble1") + testChaincode = chaincode{ + Chaincode: newLifecycleChaincode, + isLegacy: false, + } + nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) + testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") + deployChaincode(network, orderer, testChaincode) + addMarble(network, orderer, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) + assertPvtdataPresencePerCollectionConfig2(network, testChaincode.Name, "marble1") + + assertOrgRemovalBehavior() + }) }) - assertOrgRemovalBehavior() }) - Context("chaincode in new lifecycle", func() { - JustBeforeEach(func() { + When("migrating a chaincode from legacy lifecycle to new lifecycle", func() { + It("performs check against collection config from legacy lifecycle", func() { + By("deploying legacy chaincode") testChaincode = chaincode{ - Chaincode: newLifecycleChaincode, - isLegacy: false, + Chaincode: legacyChaincode, + isLegacy: true, } - nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, allPeers...) - }) - assertOrgRemovalBehavior() - }) - }) + deployChaincode(network, orderer, testChaincode) + nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) - Describe("Collection Config Updates", func() { - JustBeforeEach(func() { - By("deploying legacy chaincode") - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, - } - helper.deployChaincode(testChaincode) - }) - - When("migrating a chaincode from legacy lifecycle to new lifecycle", func() { - JustBeforeEach(func() { - nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, allPeers...) newLifecycleChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") newLifecycleChaincode.PackageID = "test-package-id" - }) - It("performs check against collection config from legacy lifecycle", func() { - helper.approveChaincodeForMyOrgExpectErr( + approveChaincodeForMyOrgExpectErr( + network, + orderer, newLifecycleChaincode, `the BlockToLive in an existing collection \[collectionMarblePrivateDetails\] modified. Existing value \[1000000\]`, - network.Peer("org2", "peer0")) + network.Peer("Org2", "peer0")) }) }) - }) - Describe("marble APIs invocation and private data delivery", func() { - // call marble APIs: getMarblesByRange, transferMarble, delete, getMarbleHash, getMarblePrivateDetailsHash and verify ACL Behavior - assertMarbleAPIs := func() { - eligiblePeer := network.Peer("org2", "peer0") - ccName := testChaincode.Name - - // Verifies marble private chaincode APIs: getMarblesByRange, transferMarble, delete + Describe("marble APIs invocation and private data delivery", func() { + // call marble APIs: getMarblesByRange, transferMarble, delete, getMarbleHash, getMarblePrivateDetailsHash and verify ACL Behavior + assertMarbleAPIs := func() { + eligiblePeer := network.Peer("Org2", "peer0") + ccName := testChaincode.Name - By("adding five marbles") - for i := 0; i < 5; i++ { - helper.addMarble(ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) - } + // Verifies marble private chaincode APIs: getMarblesByRange, transferMarble, delete - By("getting marbles by range") - expectedMsg := `\Q[{"Key":"test-marble-0", "Record":{"docType":"marble","name":"test-marble-0","color":"blue","size":35,"owner":"tom"}},{"Key":"test-marble-1", "Record":{"docType":"marble","name":"test-marble-1","color":"blue","size":35,"owner":"tom"}}]\E` - helper.assertGetMarblesByRange(ccName, `"test-marble-0", "test-marble-2"`, expectedMsg, eligiblePeer) + By("adding five marbles") + for i := 0; i < 5; i++ { + addMarble(network, orderer, ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) + } - By("transferring test-marble-0 to jerry") - helper.transferMarble(ccName, `{"name":"test-marble-0", "owner":"jerry"}`, eligiblePeer) + By("getting marbles by range") + assertGetMarblesByRange(network, ccName, `"test-marble-0", "test-marble-2"`, eligiblePeer) - By("verifying the new ownership of test-marble-0") - expectedMsg = fmt.Sprintf(`{"docType":"marble","name":"test-marble-0","color":"blue","size":35,"owner":"jerry"}`) - helper.assertOwnershipInCollectionM(ccName, `test-marble-0`, expectedMsg, eligiblePeer) + By("transferring test-marble-0 to jerry") + transferMarble(network, orderer, ccName, `{"name":"test-marble-0", "owner":"jerry"}`, eligiblePeer) - By("deleting test-marble-0") - helper.deleteMarble(ccName, `{"name":"test-marble-0"}`, eligiblePeer) + By("verifying the new ownership of test-marble-0") + assertOwnershipInCollectionM(network, ccName, `test-marble-0`, eligiblePeer) - By("verifying the deletion of test-marble-0") - helper.assertDoesNotExistInCollectionM(ccName, `test-marble-0`, eligiblePeer) + By("deleting test-marble-0") + deleteMarble(network, orderer, ccName, `{"name":"test-marble-0"}`, eligiblePeer) - // This section verifies that chaincode can return private data hash. - // Unlike private data that can only be accessed from authorized peers as defined in the collection config, - // private data hash can be queried on any peer in the channel that has the chaincode instantiated. - // When calling QueryChaincode with "getMarbleHash", the cc will return the private data hash in collectionMarbles. - // When calling QueryChaincode with "getMarblePrivateDetailsHash", the cc will return the private data hash in collectionMarblePrivateDetails. + By("verifying the deletion of test-marble-0") + assertDoesNotExistInCollectionM(network, ccName, `test-marble-0`, eligiblePeer) - peerList := []*nwo.Peer{ - network.Peer("org1", "peer0"), - network.Peer("org2", "peer0"), - network.Peer("org3", "peer0")} + // This section verifies that chaincode can return private data hash. + // Unlike private data that can only be accessed from authorized peers as defined in the collection config, + // private data hash can be queried on any peer in the channel that has the chaincode instantiated. + // When calling QueryChaincode with "getMarbleHash", the cc will return the private data hash in collectionMarbles. + // When calling QueryChaincode with "getMarblePrivateDetailsHash", the cc will return the private data hash in collectionMarblePrivateDetails. - By("verifying getMarbleHash is accessible from all peers that has the chaincode instantiated") - expectedBytes := util.ComputeStringHash(`{"docType":"marble","name":"test-marble-1","color":"blue","size":35,"owner":"tom"}`) - helper.assertMarblesPrivateHashM(ccName, "test-marble-1", expectedBytes, peerList) + peerList := []*nwo.Peer{ + network.Peer("Org1", "peer0"), + network.Peer("Org2", "peer0"), + network.Peer("Org3", "peer0")} - By("verifying getMarblePrivateDetailsHash is accessible from all peers that has the chaincode instantiated") - expectedBytes = util.ComputeStringHash(`{"docType":"marblePrivateDetails","name":"test-marble-1","price":99}`) - helper.assertMarblesPrivateDetailsHashMPD(ccName, "test-marble-1", expectedBytes, peerList) + By("verifying getMarbleHash is accessible from all peers that has the chaincode instantiated") + expectedBytes := util.ComputeStringHash(`{"docType":"marble","name":"test-marble-1","color":"blue","size":35,"owner":"tom"}`) + assertMarblesPrivateHashM(network, ccName, "test-marble-1", expectedBytes, peerList) - // collection ACL while reading private data: not allowed to non-members - // collections_config4: collectionMarblePrivateDetails - member_only_read is set to true + By("verifying getMarblePrivateDetailsHash is accessible from all peers that has the chaincode instantiated") + expectedBytes = util.ComputeStringHash(`{"docType":"marblePrivateDetails","name":"test-marble-1","price":99}`) + assertMarblesPrivateDetailsHashMPD(network, ccName, "test-marble-1", expectedBytes, peerList) - By("querying collectionMarblePrivateDetails on org1-peer0 by org1-user1, shouldn't have read access") - helper.assertNoReadAccessToCollectionMPD(testChaincode.Name, "test-marble-1", network.Peer("org1", "peer0")) - } + // collection ACL while reading private data: not allowed to non-members + // collections_config3: collectionMarblePrivateDetails - member_only_read is set to true - // verify DeliverWithPrivateData sends private data based on the ACL in collection config - // before and after upgrade. - assertDeliverWithPrivateDataACLBehavior := func() { - By("getting signing identity for a user in org1") - signingIdentity := getSigningIdentity(network, "org1", "User1", "Org1MSP", "bccsp") - - By("adding a marble") - peer := network.Peer("org2", "peer0") - helper.addMarble(testChaincode.Name, `{"name":"marble11", "color":"blue", "size":35, "owner":"tom", "price":99}`, peer) - - By("getting the deliver event for newest block") - event := getEventFromDeliverService(network, peer, "testchannel", signingIdentity, 0) - - By("verifying private data in deliver event contains 'collectionMarbles' only") - // it should receive pvtdata for 'collectionMarbles' only because memberOnlyRead is true - expectedKVWritesMap := map[string]map[string][]byte{ - "collectionMarbles": { - "\000color~name\000blue\000marble11\000": []byte("\000"), - "marble11": getValueForCollectionMarbles("marble11", "blue", "tom", 35), - }, + By("querying collectionMarblePrivateDetails on org1-peer0 by org1-user1, shouldn't have read access") + assertNoReadAccessToCollectionMPD(network, testChaincode.Name, "test-marble-1", network.Peer("Org1", "peer0")) } - assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) - By("upgrading chaincode with collections_config1.json where isMemberOnlyRead is false") - testChaincode.CollectionsConfig = collectionConfig("collections_config1.json") - testChaincode.Version = "1.1" - if !testChaincode.isLegacy { - testChaincode.Sequence = "2" - } - helper.upgradeChaincode(testChaincode) + // verify DeliverWithPrivateData sends private data based on the ACL in collection config + // before and after upgrade. + assertDeliverWithPrivateDataACLBehavior := func() { + By("getting signing identity for a user in org1") + signingIdentity := getSigningIdentity(network, "Org1", "User1", "Org1MSP", "bccsp") + + By("adding a marble") + peer := network.Peer("Org2", "peer0") + addMarble(network, orderer, testChaincode.Name, `{"name":"marble11", "color":"blue", "size":35, "owner":"tom", "price":99}`, peer) + + By("getting the deliver event for newest block") + event := getEventFromDeliverService(network, peer, channelID, signingIdentity, 0) + + By("verifying private data in deliver event contains 'collectionMarbles' only") + // it should receive pvtdata for 'collectionMarbles' only because memberOnlyRead is true + expectedKVWritesMap := map[string]map[string][]byte{ + "collectionMarbles": { + "\000color~name\000blue\000marble11\000": []byte("\000"), + "marble11": getValueForCollectionMarbles("marble11", "blue", "tom", 35), + }, + } + assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) - By("getting the deliver event for an old block committed before upgrade") - event = getEventFromDeliverService(network, peer, "testchannel", signingIdentity, event.BlockNum) + By("upgrading chaincode with collections_config1.json where isMemberOnlyRead is false") + testChaincode.CollectionsConfig = collectionConfig("collections_config1.json") + testChaincode.Version = "1.1" + if !testChaincode.isLegacy { + testChaincode.Sequence = "2" + } + upgradeChaincode(network, orderer, testChaincode) - By("verifying the deliver event for the old block uses old config") - assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) + By("getting the deliver event for an old block committed before upgrade") + event = getEventFromDeliverService(network, peer, channelID, signingIdentity, event.BlockNum) - By("adding a new marble after upgrade") - helper.addMarble(testChaincode.Name, - `{"name":"marble12", "color":"blue", "size":35, "owner":"tom", "price":99}`, - network.Peer("org1", "peer0"), - ) - By("getting the deliver event for a new block committed after upgrade") - event = getEventFromDeliverService(network, peer, "testchannel", signingIdentity, 0) - - // it should receive pvtdata for both collections because memberOnlyRead is false - By("verifying the deliver event for the new block uses new config") - expectedKVWritesMap = map[string]map[string][]byte{ - "collectionMarbles": { - "\000color~name\000blue\000marble12\000": []byte("\000"), - "marble12": getValueForCollectionMarbles("marble12", "blue", "tom", 35), - }, - "collectionMarblePrivateDetails": { - "marble12": getValueForCollectionMarblePrivateDetails("marble12", 99), - }, - } - assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) - } + By("verifying the deliver event for the old block uses old config") + assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) - Context("chaincode in legacy lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: legacyChaincode, - isLegacy: true, + By("adding a new marble after upgrade") + addMarble(network, orderer, testChaincode.Name, + `{"name":"marble12", "color":"blue", "size":35, "owner":"tom", "price":99}`, + network.Peer("Org1", "peer0"), + ) + By("getting the deliver event for a new block committed after upgrade") + event = getEventFromDeliverService(network, peer, channelID, signingIdentity, 0) + + // it should receive pvtdata for both collections because memberOnlyRead is false + By("verifying the deliver event for the new block uses new config") + expectedKVWritesMap = map[string]map[string][]byte{ + "collectionMarbles": { + "\000color~name\000blue\000marble12\000": []byte("\000"), + "marble12": getValueForCollectionMarbles("marble12", "blue", "tom", 35), + }, + "collectionMarblePrivateDetails": { + "marble12": getValueForCollectionMarblePrivateDetails("marble12", 99), + }, } - testChaincode.CollectionsConfig = collectionConfig("collections_config4.json") - helper.deployChaincode(testChaincode) - }) + assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) + } - It("calls marbles APIs and delivers private data", func() { - assertMarbleAPIs() - assertDeliverWithPrivateDataACLBehavior() - }) - }) + When("chaincode in legacy lifecycle", func() { + It("calls marbles APIs and delivers private data", func() { + By("deploying legacy chaincode") + testChaincode = chaincode{ + Chaincode: legacyChaincode, + isLegacy: true, + } + testChaincode.CollectionsConfig = collectionConfig("collections_config3.json") + deployChaincode(network, orderer, testChaincode) - Context("chaincode in new lifecycle", func() { - JustBeforeEach(func() { - testChaincode = chaincode{ - Chaincode: newLifecycleChaincode, - isLegacy: false, - } - nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, allPeers...) - testChaincode.CollectionsConfig = collectionConfig("collections_config4.json") - helper.deployChaincode(testChaincode) + assertMarbleAPIs() + assertDeliverWithPrivateDataACLBehavior() + }) }) - It("calls marbles APIs and delivers private data", func() { - assertMarbleAPIs() - assertDeliverWithPrivateDataACLBehavior() + When("chaincode in new lifecycle", func() { + It("calls marbles APIs and delivers private data", func() { + By("deploying new lifecycle chaincode") + testChaincode = chaincode{ + Chaincode: newLifecycleChaincode, + isLegacy: false, + } + nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) + testChaincode.CollectionsConfig = collectionConfig("collections_config3.json") + deployChaincode(network, orderer, testChaincode) + + assertMarbleAPIs() + assertDeliverWithPrivateDataACLBehavior() + }) }) }) }) - }) -func initThreeOrgsSetup() (string, *nwo.Network) { +func initThreeOrgsSetup() *nwo.Network { var err error testDir, err := ioutil.TempDir("", "e2e-pvtdata") Expect(err).NotTo(HaveOccurred()) @@ -515,42 +532,61 @@ func initThreeOrgsSetup() (string, *nwo.Network) { client, err := docker.NewClientFromEnv() Expect(err).NotTo(HaveOccurred()) - configBytes, err := ioutil.ReadFile(filepath.Join("testdata", "network.yaml")) - Expect(err).NotTo(HaveOccurred()) + config := nwo.BasicSolo() - var networkConfig *nwo.Config - err = yaml.Unmarshal(configBytes, &networkConfig) - Expect(err).NotTo(HaveOccurred()) + // add org3 with one peer + config.Organizations = append(config.Organizations, &nwo.Organization{ + Name: "Org3", + MSPID: "Org3MSP", + Domain: "org3.example.com", + EnableNodeOUs: true, + Users: 2, + CA: &nwo.CA{Hostname: "ca"}, + }) + config.Consortiums[0].Organizations = append(config.Consortiums[0].Organizations, "Org3") + config.Profiles[1].Organizations = append(config.Profiles[1].Organizations, "Org3") + config.Peers = append(config.Peers, &nwo.Peer{ + Name: "peer0", + Organization: "Org3", + Channels: []*nwo.PeerChannel{ + {Name: channelID, Anchor: true}, + }, + }) - n := nwo.New(networkConfig, testDir, client, StartPort(), components) + n := nwo.New(config, testDir, client, StartPort(), components) n.GenerateConfigTree() - return testDir, n + // remove peer1 from org1 and org2 so we can add it back later, we generate the config tree above + // with the two peers so the config files exist later when adding the peer back + peers := []*nwo.Peer{} + for _, p := range n.Peers { + if p.Name != "peer1" { + peers = append(peers, p) + } + } + n.Peers = peers + Expect(n.Peers).To(HaveLen(3)) + + return n } -func startNetwork(n *nwo.Network) (ifrit.Process, *nwo.Orderer, []*nwo.Peer) { +func startNetwork(n *nwo.Network) (ifrit.Process, *nwo.Orderer) { n.Bootstrap() networkRunner := n.NetworkGroupRunner() process := ifrit.Invoke(networkRunner) Eventually(process.Ready(), n.EventuallyTimeout).Should(BeClosed()) orderer := n.Orderer("orderer") - n.CreateAndJoinChannel(orderer, "testchannel") - n.UpdateChannelAnchors(orderer, "testchannel") - - expectedPeers := []*nwo.Peer{ - n.Peer("org1", "peer0"), - n.Peer("org2", "peer0"), - n.Peer("org3", "peer0"), - } + n.CreateAndJoinChannel(orderer, channelID) + n.UpdateChannelAnchors(orderer, channelID) By("verifying membership") - n.VerifyMembership(expectedPeers, "testchannel") + n.VerifyMembership(n.Peers, channelID) - return process, orderer, expectedPeers + return process, orderer } -func testCleanup(testDir string, network *nwo.Network, process ifrit.Process) { +func testCleanup(network *nwo.Network, process ifrit.Process) { if process != nil { process.Signal(syscall.SIGTERM) Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive()) @@ -558,7 +594,7 @@ func testCleanup(testDir string, network *nwo.Network, process ifrit.Process) { if network != nil { network.Cleanup() } - os.RemoveAll(testDir) + os.RemoveAll(network.RootDir) } func collectionConfig(collConfigFile string) string { @@ -570,86 +606,82 @@ type chaincode struct { isLegacy bool } -type networkHelper struct { - *nwo.Network - orderer *nwo.Orderer - peers []*nwo.Peer - channelID string - testDir string -} +func addPeer(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer) ifrit.Process { + process := ifrit.Invoke(n.PeerRunner(peer)) + Eventually(process.Ready(), n.EventuallyTimeout).Should(BeClosed()) -func (nh *networkHelper) addPeer(peer *nwo.Peer) { - nh.JoinChannel(nh.channelID, nh.orderer, peer) - peer.Channels = append(peer.Channels, &nwo.PeerChannel{Name: nh.channelID, Anchor: false}) - ledgerHeight := nwo.GetLedgerHeight(nh.Network, nh.peers[0], nh.channelID) - sess, err := nh.PeerAdminSession( + n.JoinChannel(channelID, orderer, peer) + ledgerHeight := nwo.GetLedgerHeight(n, n.Peers[0], channelID) + sess, err := n.PeerAdminSession( peer, commands.ChannelFetch{ Block: "newest", - ChannelID: nh.channelID, - Orderer: nh.OrdererAddress(nh.orderer, nwo.ListenPort), - OutputFile: filepath.Join(nh.testDir, "newest_block.pb"), + ChannelID: channelID, + Orderer: n.OrdererAddress(orderer, nwo.ListenPort), + OutputFile: filepath.Join(n.RootDir, "newest_block.pb"), }, ) Expect(err).NotTo(HaveOccurred()) - Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0)) + Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) Expect(sess.Err).To(gbytes.Say(fmt.Sprintf("Received block: %d", ledgerHeight-1))) - nh.peers = append(nh.peers, peer) - nwo.WaitUntilEqualLedgerHeight(nh.Network, nh.channelID, nwo.GetLedgerHeight(nh.Network, nh.peers[0], nh.channelID), nh.peers...) + n.Peers = append(n.Peers, peer) + nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, n.Peers[0], channelID), n.Peers...) + + return process } -func (nh *networkHelper) deployChaincode(chaincode chaincode) { +func deployChaincode(n *nwo.Network, orderer *nwo.Orderer, chaincode chaincode) { if chaincode.isLegacy { - nwo.DeployChaincodeLegacy(nh.Network, nh.channelID, nh.orderer, chaincode.Chaincode) + nwo.DeployChaincodeLegacy(n, channelID, orderer, chaincode.Chaincode) } else { - nwo.DeployChaincode(nh.Network, nh.channelID, nh.orderer, chaincode.Chaincode) + nwo.DeployChaincode(n, channelID, orderer, chaincode.Chaincode) } } -func (nh *networkHelper) upgradeChaincode(chaincode chaincode) { +func upgradeChaincode(n *nwo.Network, orderer *nwo.Orderer, chaincode chaincode) { if chaincode.isLegacy { - nwo.UpgradeChaincodeLegacy(nh.Network, nh.channelID, nh.orderer, chaincode.Chaincode) + nwo.UpgradeChaincodeLegacy(n, channelID, orderer, chaincode.Chaincode) } else { - nwo.DeployChaincode(nh.Network, nh.channelID, nh.orderer, chaincode.Chaincode) + nwo.DeployChaincode(n, channelID, orderer, chaincode.Chaincode) } } -func (nh *networkHelper) installChaincode(chaincode chaincode, peer *nwo.Peer) { +func installChaincode(n *nwo.Network, chaincode chaincode, peer *nwo.Peer) { if chaincode.isLegacy { - nwo.InstallChaincodeLegacy(nh.Network, chaincode.Chaincode, peer) + nwo.InstallChaincodeLegacy(n, chaincode.Chaincode, peer) } else { - nwo.PackageAndInstallChaincode(nh.Network, chaincode.Chaincode, peer) + nwo.PackageAndInstallChaincode(n, chaincode.Chaincode, peer) } } -func (nh *networkHelper) queryChaincode(peer *nwo.Peer, command commands.ChaincodeQuery, expectedMessage string, expectSuccess bool) { - sess, err := nh.PeerUserSession(peer, "User1", command) +func queryChaincode(n *nwo.Network, peer *nwo.Peer, command commands.ChaincodeQuery, expectedMessage string, expectSuccess bool) { + sess, err := n.PeerUserSession(peer, "User1", command) Expect(err).NotTo(HaveOccurred()) if expectSuccess { - Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0)) + Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) Expect(sess).To(gbytes.Say(expectedMessage)) } else { - Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit()) + Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) Expect(sess.Err).To(gbytes.Say(expectedMessage)) } } -func (nh *networkHelper) invokeChaincode(peer *nwo.Peer, command commands.ChaincodeInvoke) { - sess, err := nh.PeerUserSession(peer, "User1", command) +func invokeChaincode(n *nwo.Network, peer *nwo.Peer, command commands.ChaincodeInvoke) { + sess, err := n.PeerUserSession(peer, "User1", command) Expect(err).NotTo(HaveOccurred()) - Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0)) + Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful.")) } -func (nh *networkHelper) approveChaincodeForMyOrgExpectErr(chaincode nwo.Chaincode, expectedErrMsg string, peers ...*nwo.Peer) { +func approveChaincodeForMyOrgExpectErr(n *nwo.Network, orderer *nwo.Orderer, chaincode nwo.Chaincode, expectedErrMsg string, peers ...*nwo.Peer) { // used to ensure we only approve once per org approvedOrgs := map[string]bool{} for _, p := range peers { if _, ok := approvedOrgs[p.Organization]; !ok { - sess, err := nh.PeerAdminSession(p, commands.ChaincodeApproveForMyOrg{ - ChannelID: nh.channelID, - Orderer: nh.OrdererAddress(nh.orderer, nwo.ListenPort), + sess, err := n.PeerAdminSession(p, commands.ChaincodeApproveForMyOrg{ + ChannelID: channelID, + Orderer: n.OrdererAddress(orderer, nwo.ListenPort), Name: chaincode.Name, Version: chaincode.Version, PackageID: chaincode.PackageID, @@ -662,264 +694,212 @@ func (nh *networkHelper) approveChaincodeForMyOrgExpectErr(chaincode nwo.Chainco CollectionsConfig: chaincode.CollectionsConfig, }) Expect(err).NotTo(HaveOccurred()) - Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit()) + Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) approvedOrgs[p.Organization] = true - Eventually(sess.Err, nh.EventuallyTimeout).Should(gbytes.Say(expectedErrMsg)) + Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(expectedErrMsg)) } } } -type testHelper struct { - *networkHelper -} - -func (th *testHelper) addMarble(chaincodeName, marbleDetails string, peer *nwo.Peer) { +func addMarble(n *nwo.Network, orderer *nwo.Orderer, chaincodeName, marbleDetails string, peer *nwo.Peer) { marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDetails)) command := commands.ChaincodeInvoke{ - ChannelID: th.channelID, - Orderer: th.OrdererAddress(th.orderer, nwo.ListenPort), + ChannelID: channelID, + Orderer: n.OrdererAddress(orderer, nwo.ListenPort), Name: chaincodeName, Ctor: fmt.Sprintf(`{"Args":["initMarble"]}`), Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64), PeerAddresses: []string{ - th.PeerAddress(peer, nwo.ListenPort), + n.PeerAddress(peer, nwo.ListenPort), }, WaitForEvent: true, } - th.invokeChaincode(peer, command) - nwo.WaitUntilEqualLedgerHeight(th.Network, th.channelID, nwo.GetLedgerHeight(th.Network, peer, th.channelID), th.peers...) + invokeChaincode(n, peer, command) + nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, peer, channelID), n.Peers...) } -func (th *testHelper) deleteMarble(chaincodeName, marbleDelete string, peer *nwo.Peer) { +func deleteMarble(n *nwo.Network, orderer *nwo.Orderer, chaincodeName, marbleDelete string, peer *nwo.Peer) { marbleDeleteBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDelete)) command := commands.ChaincodeInvoke{ - ChannelID: th.channelID, - Orderer: th.OrdererAddress(th.orderer, nwo.ListenPort), + ChannelID: channelID, + Orderer: n.OrdererAddress(orderer, nwo.ListenPort), Name: chaincodeName, Ctor: fmt.Sprintf(`{"Args":["delete"]}`), Transient: fmt.Sprintf(`{"marble_delete":"%s"}`, marbleDeleteBase64), PeerAddresses: []string{ - th.PeerAddress(peer, nwo.ListenPort), + n.PeerAddress(peer, nwo.ListenPort), }, WaitForEvent: true, } - th.invokeChaincode(peer, command) - nwo.WaitUntilEqualLedgerHeight(th.Network, th.channelID, nwo.GetLedgerHeight(th.Network, peer, th.channelID), th.peers...) -} - -func (th *testHelper) assertGetMarblesByRange(chaincodeName, marbleRange string, expectedMsg string, peer *nwo.Peer) { - - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["getMarblesByRange", %s]}`, marbleRange), - } - th.queryChaincode(peer, command, expectedMsg, true) + invokeChaincode(n, peer, command) + nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, peer, channelID), n.Peers...) } -func (th *testHelper) transferMarble(chaincodeName, marbleOwner string, peer *nwo.Peer) { +func transferMarble(n *nwo.Network, orderer *nwo.Orderer, chaincodeName, marbleOwner string, peer *nwo.Peer) { marbleOwnerBase64 := base64.StdEncoding.EncodeToString([]byte(marbleOwner)) command := commands.ChaincodeInvoke{ - ChannelID: th.channelID, - Orderer: th.OrdererAddress(th.orderer, nwo.ListenPort), + ChannelID: channelID, + Orderer: n.OrdererAddress(orderer, nwo.ListenPort), Name: chaincodeName, Ctor: fmt.Sprintf(`{"Args":["transferMarble"]}`), Transient: fmt.Sprintf(`{"marble_owner":"%s"}`, marbleOwnerBase64), PeerAddresses: []string{ - th.PeerAddress(peer, nwo.ListenPort), + n.PeerAddress(peer, nwo.ListenPort), }, WaitForEvent: true, } - th.invokeChaincode(peer, command) - nwo.WaitUntilEqualLedgerHeight(th.Network, th.channelID, nwo.GetLedgerHeight(th.Network, peer, th.channelID), th.peers...) + invokeChaincode(n, peer, command) + nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, peer, channelID), n.Peers...) } -func (th *testHelper) assertPvtdataPresencePerCollectionConfig1(chaincodeName, marbleName string, peers ...*nwo.Peer) { +func assertPvtdataPresencePerCollectionConfig1(n *nwo.Network, chaincodeName, marbleName string, peers ...*nwo.Peer) { if len(peers) == 0 { - peers = th.peers + peers = n.Peers } for _, peer := range peers { switch peer.Organization { - case "org1": - th.assertPresentInCollectionM(chaincodeName, marbleName, peer) - th.assertNotPresentInCollectionMPD(chaincodeName, marbleName, peer) + case "Org1": + assertPresentInCollectionM(n, chaincodeName, marbleName, peer) + assertNotPresentInCollectionMPD(n, chaincodeName, marbleName, peer) - case "org2": - th.assertPresentInCollectionM(chaincodeName, marbleName, peer) - th.assertPresentInCollectionMPD(chaincodeName, marbleName, peer) + case "Org2": + assertPresentInCollectionM(n, chaincodeName, marbleName, peer) + assertPresentInCollectionMPD(n, chaincodeName, marbleName, peer) - case "org3": - th.assertNotPresentInCollectionM(chaincodeName, marbleName, peer) - th.assertPresentInCollectionMPD(chaincodeName, marbleName, peer) + case "Org3": + assertNotPresentInCollectionM(n, chaincodeName, marbleName, peer) + assertPresentInCollectionMPD(n, chaincodeName, marbleName, peer) } } } -func (th *testHelper) assertPvtdataPresencePerCollectionConfig2(chaincodeName, marbleName string, peers ...*nwo.Peer) { +func assertPvtdataPresencePerCollectionConfig2(n *nwo.Network, chaincodeName, marbleName string, peers ...*nwo.Peer) { if len(peers) == 0 { - peers = th.peers + peers = n.Peers } for _, peer := range peers { switch peer.Organization { - case "org1": - th.assertPresentInCollectionM(chaincodeName, marbleName, peer) - th.assertNotPresentInCollectionMPD(chaincodeName, marbleName, peer) + case "Org1": + assertPresentInCollectionM(n, chaincodeName, marbleName, peer) + assertNotPresentInCollectionMPD(n, chaincodeName, marbleName, peer) - case "org2", "org3": - th.assertPresentInCollectionM(chaincodeName, marbleName, peer) - th.assertPresentInCollectionMPD(chaincodeName, marbleName, peer) + case "Org2", "Org3": + assertPresentInCollectionM(n, chaincodeName, marbleName, peer) + assertPresentInCollectionMPD(n, chaincodeName, marbleName, peer) } } } -func (th *testHelper) assertPvtdataPresencePerCollectionConfig5(chaincodeName, marbleName string, peers ...*nwo.Peer) { - th.assertPvtdataPresencePerCollectionConfig1(chaincodeName, marbleName, peers...) +// assertGetMarblesByRange asserts that +func assertGetMarblesByRange(n *nwo.Network, chaincodeName, marbleRange string, peer *nwo.Peer) { + query := fmt.Sprintf(`{"Args":["getMarblesByRange", %s]}`, marbleRange) + expectedMsg := `\Q[{"Key":"test-marble-0", "Record":{"docType":"marble","name":"test-marble-0","color":"blue","size":35,"owner":"tom"}},{"Key":"test-marble-1", "Record":{"docType":"marble","name":"test-marble-1","color":"blue","size":35,"owner":"tom"}}]\E` + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, true, peer) } // assertPresentInCollectionM asserts that the private data for given marble is present in collection // 'readMarble' at the given peers -func (th *testHelper) assertPresentInCollectionM(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName), - } +func assertPresentInCollectionM(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName) expectedMsg := fmt.Sprintf(`{"docType":"marble","name":"%s"`, marbleName) - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, true) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, true, peerList...) } // assertPresentInCollectionMPD asserts that the private data for given marble is present // in collection 'readMarblePrivateDetails' at the given peers -func (th *testHelper) assertPresentInCollectionMPD(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName), - } +func assertPresentInCollectionMPD(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName) expectedMsg := fmt.Sprintf(`{"docType":"marblePrivateDetails","name":"%s"`, marbleName) - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, true) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, true, peerList...) } // assertNotPresentInCollectionM asserts that the private data for given marble is NOT present // in collection 'readMarble' at the given peers -func (th *testHelper) assertNotPresentInCollectionM(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName), - } +func assertNotPresentInCollectionM(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName) expectedMsg := "private data matching public hash version is not available" - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, false) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, false, peerList...) } // assertNotPresentInCollectionMPD asserts that the private data for given marble is NOT present // in collection 'readMarblePrivateDetails' at the given peers -func (th *testHelper) assertNotPresentInCollectionMPD(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName), - } +func assertNotPresentInCollectionMPD(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName) expectedMsg := "private data matching public hash version is not available" - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, false) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, false, peerList...) } // assertDoesNotExistInCollectionM asserts that the private data for given marble // does not exist in collection 'readMarble' (i.e., is never created/has been deleted/has been purged) -func (th *testHelper) assertDoesNotExistInCollectionM(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName), - } +func assertDoesNotExistInCollectionM(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName) expectedMsg := "Marble does not exist" - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, false) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, false, peerList...) } // assertDoesNotExistInCollectionMPD asserts that the private data for given marble // does not exist in collection 'readMarblePrivateDetails' (i.e., is never created/has been deleted/has been purged) -func (th *testHelper) assertDoesNotExistInCollectionMPD(chaincodeName, marbleName string, peerList ...*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName), - } +func assertDoesNotExistInCollectionMPD(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName) expectedMsg := "Marble private details does not exist" - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, false) - } + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, false, peerList...) } // assertOwnershipInCollectionM asserts that the private data for given marble is present // in collection 'readMarble' at the given peers -func (th *testHelper) assertOwnershipInCollectionM(chaincodeName, marbleName string, expectedMsg string, peerList ...*nwo.Peer) { +func assertOwnershipInCollectionM(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName) + expectedMsg := fmt.Sprintf(`{"docType":"marble","name":"test-marble-0","color":"blue","size":35,"owner":"jerry"}`) + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, true, peerList...) +} + +// assertNoReadAccessToCollectionMPD asserts that the orgs of the given peers do not have +// read access to private data for the collection readMarblePrivateDetails +func assertNoReadAccessToCollectionMPD(n *nwo.Network, chaincodeName, marbleName string, peerList ...*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName) + expectedMsg := "tx creator does not have read access permission" + queryChaincodePerPeer(n, query, chaincodeName, expectedMsg, false, peerList...) +} + +func queryChaincodePerPeer(n *nwo.Network, query, chaincodeName, expectedMsg string, expectSuccess bool, peerList ...*nwo.Peer) { command := commands.ChaincodeQuery{ - ChannelID: th.channelID, + ChannelID: channelID, Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName), + Ctor: query, } - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, true) + queryChaincode(n, peer, command, expectedMsg, expectSuccess) } } // assertMarblesPrivateHashM asserts that getMarbleHash is accessible from all peers that has the chaincode instantiated -func (th *testHelper) assertMarblesPrivateHashM(chaincodeName, marbleName string, expectedBytes []byte, peerList []*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["getMarbleHash","%s"]}`, marbleName), - } - - verifyPvtdataHash(th.Network, command, peerList, expectedBytes) +func assertMarblesPrivateHashM(n *nwo.Network, chaincodeName, marbleName string, expectedBytes []byte, peerList []*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["getMarbleHash","%s"]}`, marbleName) + verifyPvtdataHash(n, query, chaincodeName, peerList, expectedBytes) } // assertMarblesPrivateDetailsHashMPD asserts that getMarblePrivateDetailsHash is accessible from all peers that has the chaincode instantiated -func (th *testHelper) assertMarblesPrivateDetailsHashMPD(chaincodeName, marbleName string, expectedBytes []byte, peerList []*nwo.Peer) { - command := commands.ChaincodeQuery{ - ChannelID: th.channelID, - Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["getMarblePrivateDetailsHash","%s"]}`, marbleName), - } - - verifyPvtdataHash(th.Network, command, peerList, expectedBytes) +func assertMarblesPrivateDetailsHashMPD(n *nwo.Network, chaincodeName, marbleName string, expectedBytes []byte, peerList []*nwo.Peer) { + query := fmt.Sprintf(`{"Args":["getMarblePrivateDetailsHash","%s"]}`, marbleName) + verifyPvtdataHash(n, query, chaincodeName, peerList, expectedBytes) } -// assertNoReadAccessToCollectionMPD asserts that the orgs of the given peers do not have -// read access to private data for the collection readMarblePrivateDetails -func (th *testHelper) assertNoReadAccessToCollectionMPD(chaincodeName, marbleName string, peerList ...*nwo.Peer) { +// verifyPvtdataHash verifies the private data hash matches the expected bytes. +// Cannot reuse verifyAccess because the hash bytes are not valid utf8 causing gbytes.Say to fail. +func verifyPvtdataHash(n *nwo.Network, query, chaincodeName string, peers []*nwo.Peer, expected []byte) { command := commands.ChaincodeQuery{ - ChannelID: th.channelID, + ChannelID: channelID, Name: chaincodeName, - Ctor: fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName), - } - expectedMsg := "tx creator does not have read access permission" - for _, peer := range peerList { - th.queryChaincode(peer, command, expectedMsg, false) + Ctor: query, } -} -// verifyPvtdataHash verifies the private data hash matches the expected bytes. -// Cannot reuse verifyAccess because the hash bytes are not valid utf8 causing gbytes.Say to fail. -func verifyPvtdataHash(n *nwo.Network, chaincodeQueryCmd commands.ChaincodeQuery, peers []*nwo.Peer, expected []byte) { for _, peer := range peers { - sess, err := n.PeerUserSession(peer, "User1", chaincodeQueryCmd) + sess, err := n.PeerUserSession(peer, "User1", command) Expect(err).NotTo(HaveOccurred()) Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) actual := sess.Buffer().Contents() diff --git a/integration/pvtdata/testdata/collection_configs/collections_config3.json b/integration/pvtdata/testdata/collection_configs/collections_config3.json index 3000c94b4cf..aace1abda13 100644 --- a/integration/pvtdata/testdata/collection_configs/collections_config3.json +++ b/integration/pvtdata/testdata/collection_configs/collections_config3.json @@ -4,13 +4,15 @@ "policy": "OR('Org1MSP.member', 'Org2MSP.member')", "requiredPeerCount": 1, "maxPeerCount": 2, - "blockToLive":1000000 + "blockToLive":1000000, + "memberOnlyRead": true }, { "name": "collectionMarblePrivateDetails", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", + "policy": "OR('Org2MSP.member', 'Org3MSP.member')", "requiredPeerCount": 1, "maxPeerCount": 2, - "blockToLive":1000000 + "blockToLive":1000000, + "memberOnlyRead": true } ] diff --git a/integration/pvtdata/testdata/collection_configs/collections_config4.json b/integration/pvtdata/testdata/collection_configs/collections_config4.json deleted file mode 100644 index efbcf020736..00000000000 --- a/integration/pvtdata/testdata/collection_configs/collections_config4.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "name": "collectionMarbles", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", - "requiredPeerCount": 1, - "maxPeerCount": 2, - "blockToLive":1000000, - "memberOnlyRead": true - }, - { - "name": "collectionMarblePrivateDetails", - "policy": "OR('Org2MSP.member', 'Org3MSP.member')", - "requiredPeerCount": 1, - "maxPeerCount": 2, - "blockToLive":1000000, - "memberOnlyRead": true - } -] diff --git a/integration/pvtdata/testdata/collection_configs/collections_config5.json b/integration/pvtdata/testdata/collection_configs/collections_config5.json deleted file mode 100644 index 539a3427533..00000000000 --- a/integration/pvtdata/testdata/collection_configs/collections_config5.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "name": "collectionMarbles", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 0, - "blockToLive":1000000, - "memberOnlyRead": false - }, - { - "name": "collectionMarblePrivateDetails", - "policy": "OR('Org2MSP.member', 'Org3MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 0, - "blockToLive":1000000, - "memberOnlyRead": false - } -] diff --git a/integration/pvtdata/testdata/network.yaml b/integration/pvtdata/testdata/network.yaml deleted file mode 100644 index 0f22d97254a..00000000000 --- a/integration/pvtdata/testdata/network.yaml +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 ---- -organizations: -- name: orderer-org - msp_id: OrdererOrgMSP - domain: orderer.example.com - enable_node_organizational_units: false - users: 0 - ca: - hostname: ca -- name: org1 - msp_id: Org1MSP - domain: org1.example.com - enable_node_organizational_units: true - users: 2 - ca: - hostname: ca -- name: org2 - msp_id: Org2MSP - domain: org2.example.com - enable_node_organizational_units: true - users: 2 - ca: - hostname: ca -- name: org3 - msp_id: Org3MSP - domain: org3.example.com - enable_node_organizational_units: true - users: 2 - ca: - hostname: ca - -consortiums: -- name: SampleConsortium - organizations: - - org1 - - org2 - - org3 - -consensus: - type: solo - -system_channel: - name: systemchannel - profile: ThreeOrgsOrdererGenesis - -orderers: -- name: orderer - organization: orderer-org - -orderercapabilities: - v20: false - -channels: -- name: testchannel - profile: ThreeOrgsChannel - -peers: -- name: peer0 - organization: org1 - channels: - - name: testchannel - anchor: true -- name: peer1 - organization: org1 -- name: peer0 - organization: org2 - channels: - - name: testchannel - anchor: true -- name: peer1 - organization: org2 -- name: peer0 - organization: org3 - channels: - - name: testchannel - anchor: true - -profiles: -- name: ThreeOrgsOrdererGenesis - orderers: - - orderer -- name: ThreeOrgsChannel - consortium: SampleConsortium - organizations: - - org1 - - org2 - - org3