Skip to content

Commit 6e17b23

Browse files
committed
[FAB-10484] - added e2e pvtdata btl tests
added a test that checks that private data is purged after reaching btl. added another test that spans a new peer after private data was purged, and checks that the new peer isn't getting the purged data. Change-Id: I6be9d657082da18f90fd1420929f2e531cf855e9 Signed-off-by: nirro <nirro@il.ibm.com>
1 parent f5e04a8 commit 6e17b23

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

integration/pvtdata/e2e_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@ SPDX-License-Identifier: Apache-2.0
77
package e2e
88

99
import (
10+
"encoding/json"
1011
"fmt"
1112
"io/ioutil"
1213
"os"
1314
"path/filepath"
15+
"strings"
1416
"time"
1517

1618
"github.com/hyperledger/fabric/integration/pvtdata/helpers"
1719
"github.com/hyperledger/fabric/integration/pvtdata/runner"
1820
"github.com/hyperledger/fabric/integration/pvtdata/world"
21+
"github.com/hyperledger/fabric/protos/common"
1922
. "github.com/onsi/ginkgo"
2023
. "github.com/onsi/gomega"
2124
"github.com/onsi/gomega/gbytes"
25+
"github.com/tedsuo/ifrit"
2226

2327
"github.com/fsouza/go-dockerclient"
2428
)
@@ -221,6 +225,111 @@ var _ = Describe("PrivateData-EndToEnd", func() {
221225
verifyAccessFailed(d.Chaincode.Name, d.Channel, `{"Args":["readMarble","marble2"]}`, adminPeer, "Failed to get state for marble2")
222226
})
223227
})
228+
229+
Describe("collection config BlockToLive is respected", func() {
230+
BeforeEach(func() {
231+
var err error
232+
testDir, err = ioutil.TempDir("", "e2e-pvtdata")
233+
Expect(err).NotTo(HaveOccurred())
234+
w = world.GenerateBasicConfig("solo", 1, 3, testDir, components)
235+
236+
// instantiate the chaincode with two collections:
237+
// collectionMarbles - with blockToLive=1000000
238+
// collectionMarblePrivateDetails - with blockToLive=3
239+
// will use "readMarble" to read from the first one and "readMarblePrivateDetails" from the second one.
240+
// need to make sure data is purged only on the second collection
241+
d = world.Deployment{
242+
Channel: "testchannel",
243+
Chaincode: world.Chaincode{
244+
Name: "marblesp",
245+
Version: "1.0",
246+
Path: "github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd",
247+
ExecPath: os.Getenv("PATH"),
248+
CollectionsConfigPath: filepath.Join("testdata", "collection_configs", "short_btl_config.json"),
249+
},
250+
InitArgs: `{"Args":["init"]}`,
251+
Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`,
252+
Orderer: "127.0.0.1:7050",
253+
}
254+
255+
w.SetupWorld(d)
256+
257+
By("setting up all anchor peers")
258+
setAnchorsPeerForAllOrgs(1, 3, d, w.Rootpath)
259+
260+
By("verify membership was built using discovery service")
261+
expectedDiscoveredPeers = []helpers.DiscoveredPeer{
262+
{MSPID: "Org1MSP", LedgerHeight: 0, Endpoint: "0.0.0.0:7051", Identity: "", Chaincodes: []string{}},
263+
{MSPID: "Org2MSP", LedgerHeight: 0, Endpoint: "0.0.0.0:8051", Identity: "", Chaincodes: []string{}},
264+
{MSPID: "Org3MSP", LedgerHeight: 0, Endpoint: "0.0.0.0:9051", Identity: "", Chaincodes: []string{}},
265+
}
266+
verifyMembership(w, d, expectedDiscoveredPeers)
267+
268+
By("invoking initMarble function of the chaincode")
269+
adminPeer := getPeer(0, 1, w.Rootpath)
270+
adminRunner := adminPeer.InvokeChaincode(d.Chaincode.Name, d.Channel, `{"Args":["initMarble","marble1","blue","35","tom","99"]}`, d.Orderer)
271+
err = helpers.Execute(adminRunner)
272+
Expect(err).NotTo(HaveOccurred())
273+
Expect(adminRunner.Err()).To(gbytes.Say("Chaincode invoke successful."))
274+
})
275+
276+
AfterEach(func() {
277+
if w != nil {
278+
w.Close(d)
279+
}
280+
os.RemoveAll(testDir)
281+
})
282+
283+
It("verifies private data is purged after BTL has passed and new peer doesn't pull private data that was purged", func() {
284+
adminPeer := getPeer(0, 2, testDir)
285+
By("create 4 blocks to reach BTL threshold and have marble1 private data purged")
286+
initialLedgerHeight := getLedgerHeight(0, 2, d.Channel, testDir)
287+
ledgerHeight := initialLedgerHeight
288+
verifyAccess(d.Chaincode.Name, d.Channel, `{"Args":["readMarblePrivateDetails","marble1"]}`, []*runner.Peer{adminPeer}, `{"docType":"marblePrivateDetails","name":"marble1","price":99}`)
289+
for i := 2; ledgerHeight < initialLedgerHeight+4; i++ {
290+
By(fmt.Sprintf("created %d blocks, still haven't reached BTL, should have access to private data", ledgerHeight-initialLedgerHeight))
291+
adminRunner := adminPeer.InvokeChaincode(d.Chaincode.Name, d.Channel, fmt.Sprintf(`{"Args":["initMarble","marble%d","blue%d","3%d","tom","9%d"]}`, i, i, i, i), d.Orderer)
292+
err := helpers.Execute(adminRunner)
293+
Expect(err).NotTo(HaveOccurred())
294+
Expect(adminRunner.Err()).To(gbytes.Say("Chaincode invoke successful."))
295+
ledgerHeight = getLedgerHeight(0, 2, d.Channel, testDir)
296+
}
297+
By("querying collectionMarbles by peer0.org2, marble1 should still be available")
298+
verifyAccess(d.Chaincode.Name, d.Channel, `{"Args":["readMarble","marble1"]}`, []*runner.Peer{adminPeer}, `{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}`)
299+
By("querying collectionMarblePrivateDetails by peer0.org2, marble1 should have been purged")
300+
verifyAccessFailed(d.Chaincode.Name, d.Channel, `{"Args":["readMarblePrivateDetails","marble1"]}`, adminPeer, "Marble private details does not exist: marble1")
301+
302+
By("spawn a new peer peer1.org2")
303+
spawnNewPeer(w, 1, 2)
304+
adminPeer = getPeer(1, 2, testDir)
305+
EventuallyWithOffset(1, func() (*gbytes.Buffer, error) {
306+
adminRunner := adminPeer.FetchChannel(d.Channel, filepath.Join(w.Rootpath, "peer1.org2.example.com", fmt.Sprintf("%s_block.pb", d.Channel)), "0", d.Orderer)
307+
err := helpers.Execute(adminRunner)
308+
return adminRunner.Err(), err
309+
}).Should(gbytes.Say("Received block: 0"))
310+
311+
By("join peer1.org2 to the channel")
312+
EventuallyWithOffset(1, func() (*gbytes.Buffer, error) {
313+
adminRunner := adminPeer.JoinChannel(filepath.Join(w.Rootpath, "peer1.org2.example.com", fmt.Sprintf("%s_block.pb", d.Channel)))
314+
err := helpers.Execute(adminRunner)
315+
return adminRunner.Err(), err
316+
}).Should(gbytes.Say("Successfully submitted proposal to join channel"))
317+
318+
By("fetch latest blocks to peer1.org2")
319+
EventuallyWithOffset(1, func() (*gbytes.Buffer, error) {
320+
adminRunner := adminPeer.FetchChannel(d.Channel, filepath.Join(w.Rootpath, "peer1.org2.example.com", fmt.Sprintf("%s_block.pb", d.Channel)), "newest", d.Orderer)
321+
err := helpers.Execute(adminRunner)
322+
return adminRunner.Err(), err
323+
}).Should(gbytes.Say("Received block: 9"))
324+
325+
By("install the chaincode on peer1.org2 in order to query it")
326+
adminPeer.InstallChaincode("marblesp", "1.0", "github.com/hyperledger/fabric/integration/chaincode/marbles_private/cmd")
327+
328+
By("query peer1.org2, verify marble1 exist in collectionMarbles and private data doesn't exist")
329+
verifyAccess(d.Chaincode.Name, d.Channel, `{"Args":["readMarble","marble1"]}`, []*runner.Peer{adminPeer}, `{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}`)
330+
verifyAccessFailed(d.Chaincode.Name, d.Channel, `{"Args":["readMarblePrivateDetails","marble1"]}`, adminPeer, "Marble private details does not exist: marble1")
331+
})
332+
})
224333
})
225334

226335
func getPeer(peer int, org int, testDir string) *runner.Peer {
@@ -231,6 +340,18 @@ func getPeer(peer int, org int, testDir string) *runner.Peer {
231340
return adminPeer
232341
}
233342

343+
func getLedgerHeight(peer int, org int, channel string, testDir string) int {
344+
adminPeer := getPeer(peer, org, testDir)
345+
adminRunner := adminPeer.GetChannelInfo(channel)
346+
err := helpers.Execute(adminRunner)
347+
Expect(err).NotTo(HaveOccurred())
348+
349+
channelInfoStr := strings.TrimPrefix(string(adminRunner.Buffer().Contents()[:]), "Blockchain info:")
350+
var channelInfo = common.BlockchainInfo{}
351+
json.Unmarshal([]byte(channelInfoStr), &channelInfo)
352+
return int(channelInfo.Height)
353+
}
354+
234355
func setAnchorsPeerForAllOrgs(numPeers int, numOrgs int, d world.Deployment, testDir string) {
235356
for orgIndex := 1; orgIndex <= numOrgs; orgIndex++ {
236357
for peerIndex := 0; peerIndex < numPeers; peerIndex++ {
@@ -271,6 +392,28 @@ func verifyAccessFailed(ccname string, channel string, args string, peer *runner
271392
}, time.Minute).Should(gbytes.Say(expectedFailureMessage))
272393
}
273394

395+
func spawnNewPeer(w *world.World, peerIndex int, orgIndex int) {
396+
peerName := fmt.Sprintf("peer%d.org%d.example.com", peerIndex, orgIndex)
397+
if _, err := os.Stat(filepath.Join(w.Rootpath, peerName)); os.IsNotExist(err) {
398+
err := os.Mkdir(filepath.Join(w.Rootpath, peerName), 0755)
399+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
400+
}
401+
402+
helpers.CopyFile(
403+
filepath.Join("testdata", fmt.Sprintf("%s-core.yaml", peerName)),
404+
filepath.Join(w.Rootpath, peerName, "core.yaml"),
405+
)
406+
407+
peer := w.Components.Peer()
408+
peer.ConfigDir = filepath.Join(w.Rootpath, fmt.Sprintf("peer%d.org%d.example.com", peerIndex, orgIndex))
409+
peer.MSPConfigPath = filepath.Join(w.Rootpath, "crypto", "peerOrganizations", fmt.Sprintf("org%d.example.com", orgIndex),
410+
"users", fmt.Sprintf("Admin@org%d.example.com", orgIndex), "msp")
411+
peerProcess := ifrit.Invoke(peer.NodeStart(peerIndex))
412+
EventuallyWithOffset(2, peerProcess.Ready()).Should(BeClosed())
413+
ConsistentlyWithOffset(2, peerProcess.Wait()).ShouldNot(Receive())
414+
w.LocalProcess = append(w.LocalProcess, peerProcess)
415+
}
416+
274417
func verifyMembership(w *world.World, d world.Deployment, expectedDiscoveredPeers []helpers.DiscoveredPeer) {
275418
sd := getDiscoveryService(1, filepath.Join(w.Rootpath, "config_org1.yaml"), w.Rootpath)
276419
EventuallyWithOffset(1, func() bool {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[
2+
{
3+
"name": "collectionMarbles",
4+
"policy": "OR('Org1MSP.member', 'Org2MSP.member')",
5+
"requiredPeerCount": 0,
6+
"maxPeerCount": 2,
7+
"blockToLive":1000000
8+
},
9+
{
10+
"name": "collectionMarblePrivateDetails",
11+
"policy": "OR('Org2MSP.member', 'Org3MSP.member')",
12+
"requiredPeerCount": 1,
13+
"maxPeerCount": 2,
14+
"blockToLive":3
15+
}
16+
]

0 commit comments

Comments
 (0)