github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/pvtdata/pvtdata_test.go (about) 1 /* 2 Copyright hechain All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pvtdata 8 9 import ( 10 "context" 11 "encoding/base64" 12 "encoding/json" 13 "fmt" 14 "io/ioutil" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "strconv" 19 "strings" 20 "syscall" 21 "time" 22 23 "github.com/golang/protobuf/proto" 24 "github.com/golang/protobuf/ptypes" 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/gomega" 27 "github.com/pkg/errors" 28 "google.golang.org/grpc" 29 30 docker "github.com/fsouza/go-dockerclient" 31 "github.com/hechain20/hechain/common/crypto" 32 "github.com/hechain20/hechain/core/ledger/util" 33 "github.com/hechain20/hechain/integration/nwo" 34 "github.com/hechain20/hechain/integration/nwo/commands" 35 "github.com/hechain20/hechain/integration/pvtdata/marblechaincodeutil" 36 "github.com/hechain20/hechain/msp" 37 "github.com/hechain20/hechain/protoutil" 38 cb "github.com/hyperledger/fabric-protos-go/common" 39 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 40 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 41 mspp "github.com/hyperledger/fabric-protos-go/msp" 42 ab "github.com/hyperledger/fabric-protos-go/orderer" 43 pb "github.com/hyperledger/fabric-protos-go/peer" 44 "github.com/onsi/gomega/gbytes" 45 "github.com/onsi/gomega/gexec" 46 "github.com/tedsuo/ifrit" 47 "github.com/tedsuo/ifrit/grouper" 48 ) 49 50 // The chaincode used in these tests has two collections defined: 51 // collectionMarbles and collectionMarblePrivateDetails 52 // when calling QueryChaincode with first arg "readMarble", it will query collectionMarbles 53 // when calling QueryChaincode with first arg "readMarblePrivateDetails", it will query collectionMarblePrivateDetails 54 55 const channelID = "testchannel" 56 57 var _ bool = Describe("PrivateData", func() { 58 var ( 59 network *nwo.Network 60 process ifrit.Process 61 62 orderer *nwo.Orderer 63 ) 64 65 AfterEach(func() { 66 testCleanup(network, process) 67 }) 68 69 Describe("Dissemination when pulling and reconciliation are disabled", func() { 70 BeforeEach(func() { 71 By("setting up the network") 72 network = initThreeOrgsSetup(true) 73 74 By("setting the pull retry threshold to 0 and disabling reconciliation on all peers") 75 for _, p := range network.Peers { 76 core := network.ReadPeerConfig(p) 77 core.Peer.Gossip.PvtData.PullRetryThreshold = 0 78 core.Peer.Gossip.PvtData.ReconciliationEnabled = false 79 network.WritePeerConfig(p, core) 80 } 81 82 By("starting the network") 83 process, orderer = startNetwork(network) 84 }) 85 86 It("disseminates private data per collections_config1 (positive test) and collections_config8 (negative test)", func() { 87 By("deploying legacy chaincode and adding marble1") 88 testChaincode := chaincode{ 89 Chaincode: nwo.Chaincode{ 90 Name: "marblesp", 91 Version: "1.0", 92 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 93 Ctor: `{"Args":["init"]}`, 94 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 95 // collections_config1.json defines the access as follows: 96 // 1. collectionMarbles - Org1, Org2 have access to this collection 97 // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection 98 CollectionsConfig: collectionConfig("collections_config1.json"), 99 }, 100 isLegacy: true, 101 } 102 deployChaincode(network, orderer, testChaincode) 103 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, 104 `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, 105 network.Peer("Org1", "peer0"), 106 ) 107 108 assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1") 109 110 By("deploying chaincode with RequiredPeerCount greater than number of peers, endorsement will fail") 111 testChaincodeHighRequiredPeerCount := chaincode{ 112 Chaincode: nwo.Chaincode{ 113 Name: "marblespHighRequiredPeerCount", 114 Version: "1.0", 115 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 116 Ctor: `{"Args":["init"]}`, 117 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 118 CollectionsConfig: collectionConfig("collections_config8_high_requiredPeerCount.json"), 119 }, 120 isLegacy: true, 121 } 122 deployChaincode(network, orderer, testChaincodeHighRequiredPeerCount) 123 124 // attempt to add a marble with insufficient dissemination to meet RequiredPeerCount 125 marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(`{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`)) 126 127 command := commands.ChaincodeInvoke{ 128 ChannelID: channelID, 129 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 130 Name: testChaincodeHighRequiredPeerCount.Name, 131 Ctor: `{"Args":["initMarble"]}`, 132 Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64), 133 PeerAddresses: []string{ 134 network.PeerAddress(network.Peer("Org1", "peer0"), nwo.ListenPort), 135 }, 136 WaitForEvent: true, 137 } 138 expectedErrMsg := `Error: endorsement failure during invoke. response: status:500 message:"error in simulation: failed to distribute private collection` 139 invokeChaincodeExpectErr(network, network.Peer("Org1", "peer0"), command, expectedErrMsg) 140 }) 141 142 When("collection config does not have maxPeerCount or requiredPeerCount", func() { 143 It("disseminates private data per collections_config7 with default maxPeerCount and requiredPeerCount", func() { 144 By("deploying legacy chaincode and adding marble1") 145 testChaincode := chaincode{ 146 Chaincode: nwo.Chaincode{ 147 Name: "marblesp", 148 Version: "1.0", 149 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 150 Ctor: `{"Args":["init"]}`, 151 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 152 // collections_config1.json defines the access as follows: 153 // 1. collectionMarbles - Org1, Org2 have access to this collection 154 // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection 155 CollectionsConfig: collectionConfig("collections_config7.json"), 156 }, 157 isLegacy: true, 158 } 159 deployChaincode(network, orderer, testChaincode) 160 peer := network.Peer("Org1", "peer0") 161 By("adding marble1") 162 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, 163 `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, 164 peer, 165 ) 166 167 By("asserting pvtdata in each collection for config7") 168 assertPvtdataPresencePerCollectionConfig7(network, testChaincode.Name, "marble1", peer) 169 }) 170 }) 171 }) 172 173 Describe("Pvtdata behavior when a peer with new certs joins the network", func() { 174 var peerProcesses map[string]ifrit.Process 175 176 BeforeEach(func() { 177 By("setting up the network") 178 network = initThreeOrgsSetup(true) 179 180 By("starting the network") 181 peerProcesses = make(map[string]ifrit.Process) 182 network.Bootstrap() 183 184 members := grouper.Members{ 185 {Name: "brokers", Runner: network.BrokerGroupRunner()}, 186 {Name: "orderers", Runner: network.OrdererGroupRunner()}, 187 } 188 networkRunner := grouper.NewOrdered(syscall.SIGTERM, members) 189 process = ifrit.Invoke(networkRunner) 190 Eventually(process.Ready()).Should(BeClosed()) 191 192 org1peer0 := network.Peer("Org1", "peer0") 193 org2peer0 := network.Peer("Org2", "peer0") 194 org3peer0 := network.Peer("Org3", "peer0") 195 196 testPeers := []*nwo.Peer{org1peer0, org2peer0, org3peer0} 197 for _, peer := range testPeers { 198 pr := network.PeerRunner(peer) 199 p := ifrit.Invoke(pr) 200 peerProcesses[peer.ID()] = p 201 Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed()) 202 } 203 204 orderer = network.Orderer("orderer") 205 network.CreateAndJoinChannel(orderer, channelID) 206 network.UpdateChannelAnchors(orderer, channelID) 207 208 By("verifying membership") 209 network.VerifyMembership(network.Peers, channelID) 210 211 By("installing and instantiating chaincode on all peers") 212 testChaincode := chaincode{ 213 Chaincode: nwo.Chaincode{ 214 Name: "marblesp", 215 Version: "1.0", 216 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 217 Ctor: `{"Args":["init"]}`, 218 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 219 CollectionsConfig: filepath.Join("testdata", "collection_configs", "collections_config1.json"), 220 }, 221 isLegacy: true, 222 } 223 deployChaincode(network, orderer, testChaincode) 224 225 By("adding marble1 with an org 1 peer as endorser") 226 peer := network.Peer("Org1", "peer0") 227 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 228 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, marbleDetails, peer) 229 230 By("waiting for block to propagate") 231 nwo.WaitUntilEqualLedgerHeight(network, channelID, nwo.GetLedgerHeight(network, network.Peers[0], channelID), network.Peers...) 232 233 org2Peer1 := &nwo.Peer{ 234 Name: "peer1", 235 Organization: "Org2", 236 Channels: []*nwo.PeerChannel{}, // Don't set channels here so the UpdateConfig call doesn't try to fetch blocks for org2Peer1 with the default Admin user 237 } 238 network.Peers = append(network.Peers, org2Peer1) 239 }) 240 241 AfterEach(func() { 242 for _, peerProcess := range peerProcesses { 243 if peerProcess != nil { 244 peerProcess.Signal(syscall.SIGTERM) 245 Eventually(peerProcess.Wait(), network.EventuallyTimeout).Should(Receive()) 246 } 247 } 248 }) 249 250 It("verifies private data is pulled when joining a new peer with new certs", func() { 251 By("generating new certs for org2Peer1") 252 org2Peer1 := network.Peer("Org2", "peer1") 253 tempCryptoDir, err := ioutil.TempDir("", "crypto") 254 Expect(err).NotTo(HaveOccurred()) 255 defer os.RemoveAll(tempCryptoDir) 256 generateNewCertsForPeer(network, tempCryptoDir, org2Peer1) 257 258 By("updating the channel config with the new certs") 259 updateConfigWithNewCertsForPeer(network, tempCryptoDir, orderer, org2Peer1) 260 261 By("starting the peer1.org2 process") 262 pr := network.PeerRunner(org2Peer1) 263 p := ifrit.Invoke(pr) 264 peerProcesses[org2Peer1.ID()] = p 265 Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed()) 266 267 By("joining peer1.org2 to the channel with its Admin2 user") 268 tempFile, err := ioutil.TempFile("", "genesis-block") 269 Expect(err).NotTo(HaveOccurred()) 270 tempFile.Close() 271 defer os.Remove(tempFile.Name()) 272 273 sess, err := network.PeerUserSession(org2Peer1, "Admin2", commands.ChannelFetch{ 274 Block: "0", 275 ChannelID: channelID, 276 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 277 OutputFile: tempFile.Name(), 278 }) 279 Expect(err).NotTo(HaveOccurred()) 280 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 281 282 sess, err = network.PeerUserSession(org2Peer1, "Admin2", commands.ChannelJoin{ 283 BlockPath: tempFile.Name(), 284 }) 285 Expect(err).NotTo(HaveOccurred()) 286 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 287 288 org2Peer1.Channels = append(org2Peer1.Channels, &nwo.PeerChannel{Name: channelID, Anchor: false}) 289 290 ledgerHeight := nwo.GetLedgerHeight(network, network.Peers[0], channelID) 291 292 By("fetching latest blocks to peer1.org2") 293 // Retry channel fetch until peer1.org2 retrieves latest block 294 // Channel Fetch will repeatedly fail until org2Peer1 commits the config update adding its new cert 295 Eventually(fetchBlocksForPeer(network, org2Peer1, "Admin2"), network.EventuallyTimeout).Should(gbytes.Say(fmt.Sprintf("Received block: %d", ledgerHeight-1))) 296 297 By("installing chaincode on peer1.org2 to be able to query it") 298 chaincode := nwo.Chaincode{ 299 Name: "marblesp", 300 Version: "1.0", 301 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 302 Ctor: `{"Args":["init"]}`, 303 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 304 CollectionsConfig: filepath.Join("testdata", "collection_configs", "collections_config1.json"), 305 } 306 307 sess, err = network.PeerUserSession(org2Peer1, "Admin2", commands.ChaincodeInstallLegacy{ 308 Name: chaincode.Name, 309 Version: chaincode.Version, 310 Path: chaincode.Path, 311 Lang: chaincode.Lang, 312 PackageFile: chaincode.PackageFile, 313 ClientAuth: network.ClientAuthRequired, 314 }) 315 Expect(err).NotTo(HaveOccurred()) 316 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 317 318 sess, err = network.PeerUserSession(org2Peer1, "Admin2", commands.ChaincodeListInstalledLegacy{ 319 ClientAuth: network.ClientAuthRequired, 320 }) 321 Expect(err).NotTo(HaveOccurred()) 322 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 323 Expect(sess).To(gbytes.Say(fmt.Sprintf("Name: %s, Version: %s,", chaincode.Name, chaincode.Version))) 324 325 expectedPeers := []*nwo.Peer{ 326 network.Peer("Org1", "peer0"), 327 network.Peer("Org2", "peer0"), 328 network.Peer("Org2", "peer1"), 329 network.Peer("Org3", "peer0"), 330 } 331 332 By("making sure all peers have the same ledger height") 333 for _, peer := range expectedPeers { 334 Eventually(func() int { 335 var ( 336 sess *gexec.Session 337 err error 338 ) 339 if peer.ID() == "Org2.peer1" { 340 // use Admin2 user for peer1.org2 341 sess, err = network.PeerUserSession(peer, "Admin2", commands.ChannelInfo{ 342 ChannelID: channelID, 343 }) 344 Expect(err).NotTo(HaveOccurred()) 345 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 346 channelInfoStr := strings.TrimPrefix(string(sess.Buffer().Contents()[:]), "Blockchain info:") 347 channelInfo := cb.BlockchainInfo{} 348 err = json.Unmarshal([]byte(channelInfoStr), &channelInfo) 349 Expect(err).NotTo(HaveOccurred()) 350 return int(channelInfo.Height) 351 } 352 353 // If not Org2.peer1, just use regular getLedgerHeight call with User1 354 return nwo.GetLedgerHeight(network, peer, channelID) 355 }(), network.EventuallyTimeout).Should(Equal(ledgerHeight)) 356 } 357 358 By("verifying membership") 359 expectedDiscoveredPeers := make([]nwo.DiscoveredPeer, 0, len(expectedPeers)) 360 for _, peer := range expectedPeers { 361 expectedDiscoveredPeers = append(expectedDiscoveredPeers, network.DiscoveredPeer(peer, "_lifecycle", "marblesp")) 362 } 363 for _, peer := range expectedPeers { 364 By(fmt.Sprintf("checking expected peers for peer: %s", peer.ID())) 365 if peer.ID() == "Org2.peer1" { 366 // use Admin2 user for peer1.org2 367 Eventually(nwo.DiscoverPeers(network, peer, "Admin2", channelID), network.EventuallyTimeout).Should(ConsistOf(expectedDiscoveredPeers)) 368 } else { 369 Eventually(nwo.DiscoverPeers(network, peer, "User1", channelID), network.EventuallyTimeout).Should(ConsistOf(expectedDiscoveredPeers)) 370 } 371 } 372 373 By("verifying peer1.org2 got the private data that was created historically") 374 sess, err = network.PeerUserSession(org2Peer1, "Admin2", commands.ChaincodeQuery{ 375 ChannelID: channelID, 376 Name: "marblesp", 377 Ctor: `{"Args":["readMarble","marble1"]}`, 378 }) 379 Expect(err).NotTo(HaveOccurred()) 380 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 381 Expect(sess).To(gbytes.Say(`{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}`)) 382 383 sess, err = network.PeerUserSession(org2Peer1, "Admin2", commands.ChaincodeQuery{ 384 ChannelID: channelID, 385 Name: "marblesp", 386 Ctor: `{"Args":["readMarblePrivateDetails","marble1"]}`, 387 }) 388 Expect(err).NotTo(HaveOccurred()) 389 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 390 Expect(sess).To(gbytes.Say(`{"docType":"marblePrivateDetails","name":"marble1","price":99}`)) 391 }) 392 }) 393 394 Describe("Pvtdata behavior with untouched peer configs", func() { 395 var ( 396 legacyChaincode nwo.Chaincode 397 newLifecycleChaincode nwo.Chaincode 398 testChaincode chaincode 399 400 org1Peer1, org2Peer1 *nwo.Peer 401 ) 402 403 BeforeEach(func() { 404 By("setting up the network") 405 network = initThreeOrgsSetup(true) 406 legacyChaincode = nwo.Chaincode{ 407 Name: "marblesp", 408 Version: "1.0", 409 Path: "github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd", 410 Ctor: `{"Args":["init"]}`, 411 Policy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 412 // collections_config1.json defines the access as follows: 413 // 1. collectionMarbles - Org1, Org2 have access to this collection 414 // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection 415 CollectionsConfig: collectionConfig("collections_config1.json"), 416 } 417 418 newLifecycleChaincode = nwo.Chaincode{ 419 Name: "marblesp", 420 Version: "1.0", 421 Path: components.Build("github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd"), 422 Lang: "binary", 423 PackageFile: filepath.Join(network.RootDir, "marbles-pvtdata.tar.gz"), 424 Label: "marbles-private-20", 425 SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 426 CollectionsConfig: collectionConfig("collections_config1.json"), 427 Sequence: "1", 428 } 429 org1Peer1 = &nwo.Peer{ 430 Name: "peer1", 431 Organization: "Org1", 432 Channels: []*nwo.PeerChannel{ 433 {Name: channelID}, 434 }, 435 } 436 org2Peer1 = &nwo.Peer{ 437 Name: "peer1", 438 Organization: "Org2", 439 Channels: []*nwo.PeerChannel{ 440 {Name: channelID}, 441 }, 442 } 443 444 process, orderer = startNetwork(network) 445 }) 446 447 Describe("Reconciliation and pulling", func() { 448 var newPeerProcess ifrit.Process 449 450 BeforeEach(func() { 451 By("deploying legacy chaincode and adding marble1") 452 testChaincode = chaincode{ 453 Chaincode: legacyChaincode, 454 isLegacy: true, 455 } 456 deployChaincode(network, orderer, testChaincode) 457 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, 458 `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, 459 network.Peer("Org1", "peer0"), 460 ) 461 }) 462 463 AfterEach(func() { 464 if newPeerProcess != nil { 465 newPeerProcess.Signal(syscall.SIGTERM) 466 Eventually(newPeerProcess.Wait(), network.EventuallyTimeout).Should(Receive()) 467 } 468 }) 469 470 assertReconcileBehavior := func() { 471 It("disseminates private data per collections_config1", func() { 472 assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1") 473 }) 474 475 When("org3 is added to collectionMarbles via chaincode upgrade with collections_config2", func() { 476 It("distributes and allows access to newly added private data per collections_config2", func() { 477 By("upgrading the chaincode and adding marble2") 478 // collections_config2.json defines the access as follows: 479 // 1. collectionMarbles - Org1, Org2 and Org3 have access to this collection 480 // 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection 481 // the change from collections_config1 - org3 was added to collectionMarbles 482 testChaincode.Version = "1.1" 483 testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") 484 if !testChaincode.isLegacy { 485 testChaincode.Sequence = "2" 486 } 487 upgradeChaincode(network, orderer, testChaincode) 488 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, 489 `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, 490 network.Peer("Org2", "peer0"), 491 ) 492 493 assertPvtdataPresencePerCollectionConfig2(network, testChaincode.Name, "marble2") 494 }) 495 }) 496 497 When("a new peer in org1 joins the channel", func() { 498 It("causes the new peer to pull the existing private data only for collectionMarbles", func() { 499 By("adding a new peer") 500 newPeerProcess = addPeer(network, orderer, org1Peer1) 501 installChaincode(network, testChaincode, org1Peer1) 502 network.VerifyMembership(network.Peers, channelID, "marblesp") 503 504 assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble1", org1Peer1) 505 }) 506 }) 507 } 508 509 When("chaincode is migrated from legacy to new lifecycle with same collection config", func() { 510 BeforeEach(func() { 511 testChaincode = chaincode{ 512 Chaincode: newLifecycleChaincode, 513 isLegacy: false, 514 } 515 nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) 516 upgradeChaincode(network, orderer, testChaincode) 517 }) 518 assertReconcileBehavior() 519 }) 520 }) 521 522 Describe("BlockToLive", func() { 523 var newPeerProcess ifrit.Process 524 525 AfterEach(func() { 526 if newPeerProcess != nil { 527 newPeerProcess.Signal(syscall.SIGTERM) 528 Eventually(newPeerProcess.Wait(), network.EventuallyTimeout).Should(Receive()) 529 } 530 }) 531 532 It("purges private data after BTL and causes new peer not to pull the purged private data", func() { 533 By("deploying new lifecycle chaincode and adding marble1") 534 testChaincode = chaincode{ 535 Chaincode: newLifecycleChaincode, 536 isLegacy: false, 537 } 538 nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) 539 540 testChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") 541 deployChaincode(network, orderer, testChaincode) 542 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) 543 544 eligiblePeer := network.Peer("Org2", "peer0") 545 ccName := testChaincode.Name 546 By("adding three blocks") 547 for i := 0; i < 3; i++ { 548 marblechaincodeutil.AddMarble(network, orderer, channelID, ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) 549 } 550 551 By("verifying that marble1 still not purged in collection MarblesPD") 552 marblechaincodeutil.AssertPresentInCollectionMPD(network, channelID, ccName, "marble1", eligiblePeer) 553 554 By("adding one more block") 555 marblechaincodeutil.AddMarble(network, orderer, channelID, ccName, `{"name":"fun-marble-3", "color":"blue", "size":35, "owner":"tom", "price":99}`, eligiblePeer) 556 557 By("verifying that marble1 purged in collection MarblesPD") 558 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, ccName, "marble1", eligiblePeer) 559 560 By("verifying that marble1 still not purged in collection Marbles") 561 marblechaincodeutil.AssertPresentInCollectionM(network, channelID, ccName, "marble1", eligiblePeer) 562 563 By("adding new peer that is eligible to receive data") 564 newPeerProcess = addPeer(network, orderer, org2Peer1) 565 installChaincode(network, testChaincode, org2Peer1) 566 network.VerifyMembership(network.Peers, channelID, ccName) 567 marblechaincodeutil.AssertPresentInCollectionM(network, channelID, ccName, "marble1", org2Peer1) 568 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(network, channelID, ccName, "marble1", org2Peer1) 569 }) 570 }) 571 572 Describe("Org removal from collection", func() { 573 assertOrgRemovalBehavior := func() { 574 By("upgrading chaincode to remove org3 from collectionMarbles") 575 testChaincode.CollectionsConfig = collectionConfig("collections_config1.json") 576 testChaincode.Version = "1.1" 577 if !testChaincode.isLegacy { 578 testChaincode.Sequence = "2" 579 } 580 upgradeChaincode(network, orderer, testChaincode) 581 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, `{"name":"marble2", "color":"yellow", "size":53, "owner":"jerry", "price":22}`, network.Peer("Org2", "peer0")) 582 assertPvtdataPresencePerCollectionConfig1(network, testChaincode.Name, "marble2") 583 } 584 585 It("causes removed org not to get new data", func() { 586 By("deploying new lifecycle chaincode and adding marble1") 587 testChaincode = chaincode{ 588 Chaincode: newLifecycleChaincode, 589 isLegacy: false, 590 } 591 nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) 592 testChaincode.CollectionsConfig = collectionConfig("collections_config2.json") 593 deployChaincode(network, orderer, testChaincode) 594 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, network.Peer("Org2", "peer0")) 595 assertPvtdataPresencePerCollectionConfig2(network, testChaincode.Name, "marble1") 596 597 assertOrgRemovalBehavior() 598 }) 599 }) 600 601 When("migrating a chaincode from legacy lifecycle to new lifecycle", func() { 602 It("performs check against collection config from legacy lifecycle", func() { 603 By("deploying legacy chaincode") 604 testChaincode = chaincode{ 605 Chaincode: legacyChaincode, 606 isLegacy: true, 607 } 608 deployChaincode(network, orderer, testChaincode) 609 nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) 610 611 newLifecycleChaincode.CollectionsConfig = collectionConfig("short_btl_config.json") 612 newLifecycleChaincode.PackageID = "test-package-id" 613 614 approveChaincodeForMyOrgExpectErr( 615 network, 616 orderer, 617 newLifecycleChaincode, 618 `the BlockToLive in an existing collection \[collectionMarblePrivateDetails\] modified. Existing value \[1000000\]`, 619 network.Peer("Org2", "peer0")) 620 }) 621 }) 622 623 Describe("Collection Config Endorsement Policy", func() { 624 When("using legacy lifecycle chaincode", func() { 625 It("ignores the collection config endorsement policy and successfully invokes the chaincode", func() { 626 testChaincode = chaincode{ 627 Chaincode: legacyChaincode, 628 isLegacy: true, 629 } 630 By("setting the collection config endorsement policy to org2 or org3 peers") 631 testChaincode.CollectionsConfig = collectionConfig("collections_config4.json") 632 633 By("deploying legacy chaincode") 634 deployChaincode(network, orderer, testChaincode) 635 636 By("adding marble1 with an org 1 peer as endorser") 637 peer := network.Peer("Org1", "peer0") 638 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 639 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, marbleDetails, peer) 640 }) 641 }) 642 643 When("using new lifecycle chaincode", func() { 644 BeforeEach(func() { 645 testChaincode = chaincode{ 646 Chaincode: newLifecycleChaincode, 647 isLegacy: false, 648 } 649 nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peers...) 650 }) 651 652 When("a peer specified in the chaincode endorsement policy but not in the collection config endorsement policy is used to invoke the chaincode", func() { 653 It("fails validation", func() { 654 By("setting the collection config endorsement policy to org2 or org3 peers") 655 testChaincode.CollectionsConfig = collectionConfig("collections_config4.json") 656 657 By("deploying new lifecycle chaincode") 658 // set collection endorsement policy to org2 or org3 659 deployChaincode(network, orderer, testChaincode) 660 661 By("adding marble1 with an org1 peer as endorser") 662 peer := network.Peer("Org1", "peer0") 663 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 664 marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDetails)) 665 666 command := commands.ChaincodeInvoke{ 667 ChannelID: channelID, 668 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 669 Name: testChaincode.Name, 670 Ctor: `{"Args":["initMarble"]}`, 671 Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64), 672 PeerAddresses: []string{ 673 network.PeerAddress(peer, nwo.ListenPort), 674 }, 675 WaitForEvent: true, 676 } 677 678 sess, err := network.PeerUserSession(peer, "User1", command) 679 Expect(err).NotTo(HaveOccurred()) 680 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 681 Expect(sess.Err).To(gbytes.Say("ENDORSEMENT_POLICY_FAILURE")) 682 }) 683 }) 684 685 When("a peer specified in the collection endorsement policy but not in the chaincode endorsement policy is used to invoke the chaincode", func() { 686 When("the collection endorsement policy is a signature policy", func() { 687 It("successfully invokes the chaincode", func() { 688 // collection config endorsement policy specifies org2 or org3 peers for endorsement 689 By("setting the collection config endorsement policy to use a signature policy") 690 testChaincode.CollectionsConfig = collectionConfig("collections_config4.json") 691 692 By("setting the chaincode endorsement policy to org1 or org2 peers") 693 testChaincode.SignaturePolicy = `OR ('Org1MSP.member','Org2MSP.member')` 694 695 By("deploying new lifecycle chaincode") 696 // set collection endorsement policy to org2 or org3 697 deployChaincode(network, orderer, testChaincode) 698 699 By("adding marble1 with an org3 peer as endorser") 700 peer := network.Peer("Org3", "peer0") 701 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 702 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, marbleDetails, peer) 703 }) 704 }) 705 706 When("the collection endorsement policy is a channel config policy reference", func() { 707 It("successfully invokes the chaincode", func() { 708 // collection config endorsement policy specifies channel config policy reference /Channel/Application/Readers 709 By("setting the collection config endorsement policy to use a channel config policy reference") 710 testChaincode.CollectionsConfig = collectionConfig("collections_config5.json") 711 712 By("setting the channel endorsement policy to org1 or org2 peers") 713 testChaincode.SignaturePolicy = `OR ('Org1MSP.member','Org2MSP.member')` 714 715 By("deploying new lifecycle chaincode") 716 deployChaincode(network, orderer, testChaincode) 717 718 By("adding marble1 with an org3 peer as endorser") 719 peer := network.Peer("Org3", "peer0") 720 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 721 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, marbleDetails, peer) 722 }) 723 }) 724 }) 725 726 When("the collection config endorsement policy specifies a semantically wrong, but well formed signature policy", func() { 727 It("fails to invoke the chaincode with an endorsement policy failure", func() { 728 By("setting the collection config endorsement policy to non existent org4 peers") 729 testChaincode.CollectionsConfig = collectionConfig("collections_config6.json") 730 731 By("deploying new lifecycle chaincode") 732 deployChaincode(network, orderer, testChaincode) 733 734 By("adding marble1 with an org1 peer as endorser") 735 peer := network.Peer("Org1", "peer0") 736 marbleDetails := `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}` 737 marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDetails)) 738 739 command := commands.ChaincodeInvoke{ 740 ChannelID: channelID, 741 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 742 Name: testChaincode.Name, 743 Ctor: `{"Args":["initMarble"]}`, 744 Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64), 745 PeerAddresses: []string{ 746 network.PeerAddress(peer, nwo.ListenPort), 747 }, 748 WaitForEvent: true, 749 } 750 751 sess, err := network.PeerUserSession(peer, "User1", command) 752 Expect(err).NotTo(HaveOccurred()) 753 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 754 Expect(sess.Err).To(gbytes.Say("ENDORSEMENT_POLICY_FAILURE")) 755 }) 756 }) 757 }) 758 }) 759 }) 760 761 Describe("marble APIs invocation and private data delivery", func() { 762 var ( 763 newLifecycleChaincode nwo.Chaincode 764 testChaincode chaincode 765 ) 766 767 BeforeEach(func() { 768 By("setting up the network") 769 network = initThreeOrgsSetup(true) 770 771 newLifecycleChaincode = nwo.Chaincode{ 772 Name: "marblesp", 773 Version: "1.0", 774 Path: components.Build("github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd"), 775 Lang: "binary", 776 PackageFile: filepath.Join(network.RootDir, "marbles-pvtdata.tar.gz"), 777 Label: "marbles-private-20", 778 SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`, 779 CollectionsConfig: collectionConfig("collections_config1.json"), 780 Sequence: "1", 781 } 782 783 // In assertDeliverWithPrivateDataACLBehavior, there is a single goroutine that communicates to DeliverService. 784 // Set DeliverService concurrency limit to 1 in order to verify that the grpc server in a peer works correctly 785 // when reaching (but not exceeding) the concurrency limit. 786 By("setting deliverservice concurrency limit to 1") 787 for _, p := range network.Peers { 788 core := network.ReadPeerConfig(p) 789 core.Peer.Limits.Concurrency.DeliverService = 1 790 network.WritePeerConfig(p, core) 791 } 792 process, orderer = startNetwork(network) 793 }) 794 795 // call marble APIs: getMarblesByRange, transferMarble, delete, getMarbleHash, getMarblePrivateDetailsHash and verify ACL Behavior 796 assertMarbleAPIs := func() { 797 eligiblePeer := network.Peer("Org2", "peer0") 798 ccName := testChaincode.Name 799 800 // Verifies marble private chaincode APIs: getMarblesByRange, transferMarble, delete 801 802 By("adding five marbles") 803 for i := 0; i < 5; i++ { 804 marblechaincodeutil.AddMarble(network, orderer, channelID, ccName, fmt.Sprintf(`{"name":"test-marble-%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), eligiblePeer) 805 } 806 807 By("getting marbles by range") 808 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` 809 marblechaincodeutil.AssertGetMarblesByRange(network, channelID, ccName, `"test-marble-0", "test-marble-2"`, expectedMsg, eligiblePeer) 810 811 By("transferring test-marble-0 to jerry") 812 marblechaincodeutil.TransferMarble(network, orderer, channelID, ccName, `{"name":"test-marble-0", "owner":"jerry"}`, eligiblePeer) 813 814 By("verifying the new ownership of test-marble-0") 815 marblechaincodeutil.AssertOwnershipInCollectionM(network, channelID, ccName, `test-marble-0`, "jerry", eligiblePeer) 816 817 By("deleting test-marble-0") 818 marblechaincodeutil.DeleteMarble(network, orderer, channelID, ccName, `{"name":"test-marble-0"}`, eligiblePeer) 819 820 By("verifying the deletion of test-marble-0") 821 marblechaincodeutil.AssertDoesNotExistInCollectionM(network, channelID, ccName, `test-marble-0`, eligiblePeer) 822 823 // This section verifies that chaincode can return private data hash. 824 // Unlike private data that can only be accessed from authorized peers as defined in the collection config, 825 // private data hash can be queried on any peer in the channel that has the chaincode instantiated. 826 // When calling QueryChaincode with "getMarbleHash", the cc will return the private data hash in collectionMarbles. 827 // When calling QueryChaincode with "getMarblePrivateDetailsHash", the cc will return the private data hash in collectionMarblePrivateDetails. 828 829 peerList := []*nwo.Peer{ 830 network.Peer("Org1", "peer0"), 831 network.Peer("Org2", "peer0"), 832 network.Peer("Org3", "peer0"), 833 } 834 835 By("verifying getMarbleHash is accessible from all peers that has the chaincode instantiated") 836 expectedBytes := util.ComputeStringHash(`{"docType":"marble","name":"test-marble-1","color":"blue","size":35,"owner":"tom"}`) 837 marblechaincodeutil.AssertMarblesPrivateHashM(network, channelID, ccName, "test-marble-1", expectedBytes, peerList) 838 839 By("verifying getMarblePrivateDetailsHash is accessible from all peers that has the chaincode instantiated") 840 expectedBytes = util.ComputeStringHash(`{"docType":"marblePrivateDetails","name":"test-marble-1","price":99}`) 841 marblechaincodeutil.AssertMarblesPrivateDetailsHashMPD(network, channelID, ccName, "test-marble-1", expectedBytes, peerList) 842 843 // collection ACL while reading private data: not allowed to non-members 844 // collections_config3: collectionMarblePrivateDetails - member_only_read is set to true 845 846 By("querying collectionMarblePrivateDetails on org1-peer0 by org1-user1, shouldn't have read access") 847 marblechaincodeutil.AssertNoReadAccessToCollectionMPD(network, channelID, testChaincode.Name, "test-marble-1", network.Peer("Org1", "peer0")) 848 } 849 850 // verify DeliverWithPrivateData sends private data based on the ACL in collection config 851 // before and after upgrade. 852 assertDeliverWithPrivateDataACLBehavior := func() { 853 By("getting signing identity for a user in org1") 854 signingIdentity := network.PeerUserSigner(network.Peer("Org1", "peer0"), "User1") 855 856 By("adding a marble") 857 peer := network.Peer("Org2", "peer0") 858 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, `{"name":"marble11", "color":"blue", "size":35, "owner":"tom", "price":99}`, peer) 859 860 By("getting the deliver event for newest block") 861 event := getEventFromDeliverService(network, peer, channelID, signingIdentity, 0) 862 863 By("verifying private data in deliver event contains 'collectionMarbles' only") 864 // it should receive pvtdata for 'collectionMarbles' only because memberOnlyRead is true 865 expectedKVWritesMap := map[string]map[string][]byte{ 866 "collectionMarbles": { 867 "\000color~name\000blue\000marble11\000": []byte("\000"), 868 "marble11": getValueForCollectionMarbles("marble11", "blue", "tom", 35), 869 }, 870 } 871 assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) 872 873 By("upgrading chaincode with collections_config1.json where isMemberOnlyRead is false") 874 testChaincode.CollectionsConfig = collectionConfig("collections_config1.json") 875 testChaincode.Version = "1.1" 876 if !testChaincode.isLegacy { 877 testChaincode.Sequence = "2" 878 } 879 upgradeChaincode(network, orderer, testChaincode) 880 881 By("getting the deliver event for an old block committed before upgrade") 882 event = getEventFromDeliverService(network, peer, channelID, signingIdentity, event.BlockNum) 883 884 By("verifying the deliver event for the old block uses old config") 885 assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) 886 887 By("adding a new marble after upgrade") 888 marblechaincodeutil.AddMarble(network, orderer, channelID, testChaincode.Name, 889 `{"name":"marble12", "color":"blue", "size":35, "owner":"tom", "price":99}`, 890 network.Peer("Org1", "peer0"), 891 ) 892 By("getting the deliver event for a new block committed after upgrade") 893 event = getEventFromDeliverService(network, peer, channelID, signingIdentity, 0) 894 895 // it should receive pvtdata for both collections because memberOnlyRead is false 896 By("verifying the deliver event for the new block uses new config") 897 expectedKVWritesMap = map[string]map[string][]byte{ 898 "collectionMarbles": { 899 "\000color~name\000blue\000marble12\000": []byte("\000"), 900 "marble12": getValueForCollectionMarbles("marble12", "blue", "tom", 35), 901 }, 902 "collectionMarblePrivateDetails": { 903 "marble12": getValueForCollectionMarblePrivateDetails("marble12", 99), 904 }, 905 } 906 assertPrivateDataAsExpected(event.BlockAndPvtData.PrivateDataMap, expectedKVWritesMap) 907 } 908 909 It("calls marbles APIs and delivers private data", func() { 910 By("deploying new lifecycle chaincode") 911 testChaincode = chaincode{ 912 Chaincode: newLifecycleChaincode, 913 isLegacy: false, 914 } 915 nwo.EnableCapabilities(network, channelID, "Application", "V2_0", orderer, network.Peers...) 916 testChaincode.CollectionsConfig = collectionConfig("collections_config3.json") 917 deployChaincode(network, orderer, testChaincode) 918 919 By("attempting to invoke chaincode from a user (org1) not in any collection member orgs (org2 and org3)") 920 peer2 := network.Peer("Org2", "peer0") 921 marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(`{"name":"memberonly-marble", "color":"blue", "size":35, "owner":"tom", "price":99}`)) 922 command := commands.ChaincodeInvoke{ 923 ChannelID: channelID, 924 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 925 Name: "marblesp", 926 Ctor: `{"Args":["initMarble"]}`, 927 Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64), 928 PeerAddresses: []string{network.PeerAddress(peer2, nwo.ListenPort)}, 929 WaitForEvent: true, 930 } 931 peer1 := network.Peer("Org1", "peer0") 932 expectedErrMsg := "tx creator does not have write access permission" 933 invokeChaincodeExpectErr(network, peer1, command, expectedErrMsg) 934 935 assertMarbleAPIs() 936 assertDeliverWithPrivateDataACLBehavior() 937 }) 938 }) 939 }) 940 941 func initThreeOrgsSetup(removePeer1 bool) *nwo.Network { 942 var err error 943 testDir, err := ioutil.TempDir("", "e2e-pvtdata") 944 Expect(err).NotTo(HaveOccurred()) 945 946 client, err := docker.NewClientFromEnv() 947 Expect(err).NotTo(HaveOccurred()) 948 949 config := nwo.FullSolo() 950 951 // add org3 with one peer 952 config.Organizations = append(config.Organizations, &nwo.Organization{ 953 Name: "Org3", 954 MSPID: "Org3MSP", 955 Domain: "org3.example.com", 956 EnableNodeOUs: true, 957 Users: 2, 958 CA: &nwo.CA{Hostname: "ca"}, 959 }) 960 config.Consortiums[0].Organizations = append(config.Consortiums[0].Organizations, "Org3") 961 config.Profiles[1].Organizations = append(config.Profiles[1].Organizations, "Org3") 962 config.Peers = append(config.Peers, &nwo.Peer{ 963 Name: "peer0", 964 Organization: "Org3", 965 Channels: []*nwo.PeerChannel{ 966 {Name: channelID, Anchor: true}, 967 }, 968 }) 969 970 n := nwo.New(config, testDir, client, StartPort(), components) 971 n.GenerateConfigTree() 972 973 if !removePeer1 { 974 Expect(n.Peers).To(HaveLen(5)) 975 return n 976 } 977 978 // remove peer1 from org1 and org2 so we can add it back later, we generate the config tree above 979 // with the two peers so the config files exist later when adding the peer back 980 peers := []*nwo.Peer{} 981 for _, p := range n.Peers { 982 if p.Name != "peer1" { 983 peers = append(peers, p) 984 } 985 } 986 n.Peers = peers 987 Expect(n.Peers).To(HaveLen(3)) 988 989 return n 990 } 991 992 func startNetwork(n *nwo.Network) (ifrit.Process, *nwo.Orderer) { 993 n.Bootstrap() 994 networkRunner := n.NetworkGroupRunner() 995 process := ifrit.Invoke(networkRunner) 996 Eventually(process.Ready(), n.EventuallyTimeout).Should(BeClosed()) 997 998 orderer := n.Orderer("orderer") 999 n.CreateAndJoinChannel(orderer, channelID) 1000 n.UpdateChannelAnchors(orderer, channelID) 1001 1002 By("verifying membership") 1003 n.VerifyMembership(n.Peers, channelID) 1004 1005 return process, orderer 1006 } 1007 1008 func testCleanup(network *nwo.Network, process ifrit.Process) { 1009 if process != nil { 1010 process.Signal(syscall.SIGTERM) 1011 Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive()) 1012 } 1013 if network != nil { 1014 network.Cleanup() 1015 } 1016 os.RemoveAll(network.RootDir) 1017 } 1018 1019 func collectionConfig(collConfigFile string) string { 1020 return filepath.Join("testdata", "collection_configs", collConfigFile) 1021 } 1022 1023 type chaincode struct { 1024 nwo.Chaincode 1025 isLegacy bool 1026 } 1027 1028 func addPeer(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer) ifrit.Process { 1029 process := ifrit.Invoke(n.PeerRunner(peer)) 1030 Eventually(process.Ready(), n.EventuallyTimeout).Should(BeClosed()) 1031 1032 n.JoinChannel(channelID, orderer, peer) 1033 ledgerHeight := nwo.GetLedgerHeight(n, n.Peers[0], channelID) 1034 sess, err := n.PeerAdminSession( 1035 peer, 1036 commands.ChannelFetch{ 1037 Block: "newest", 1038 ChannelID: channelID, 1039 Orderer: n.OrdererAddress(orderer, nwo.ListenPort), 1040 OutputFile: filepath.Join(n.RootDir, "newest_block.pb"), 1041 }, 1042 ) 1043 Expect(err).NotTo(HaveOccurred()) 1044 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 1045 Expect(sess.Err).To(gbytes.Say(fmt.Sprintf("Received block: %d", ledgerHeight-1))) 1046 1047 n.Peers = append(n.Peers, peer) 1048 nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, n.Peers[0], channelID), n.Peers...) 1049 1050 return process 1051 } 1052 1053 func deployChaincode(n *nwo.Network, orderer *nwo.Orderer, chaincode chaincode) { 1054 if chaincode.isLegacy { 1055 nwo.DeployChaincodeLegacy(n, channelID, orderer, chaincode.Chaincode) 1056 } else { 1057 nwo.DeployChaincode(n, channelID, orderer, chaincode.Chaincode) 1058 } 1059 } 1060 1061 func upgradeChaincode(n *nwo.Network, orderer *nwo.Orderer, chaincode chaincode) { 1062 if chaincode.isLegacy { 1063 nwo.UpgradeChaincodeLegacy(n, channelID, orderer, chaincode.Chaincode) 1064 } else { 1065 nwo.DeployChaincode(n, channelID, orderer, chaincode.Chaincode) 1066 } 1067 } 1068 1069 func installChaincode(n *nwo.Network, chaincode chaincode, peer *nwo.Peer) { 1070 if chaincode.isLegacy { 1071 nwo.InstallChaincodeLegacy(n, chaincode.Chaincode, peer) 1072 } else { 1073 nwo.PackageAndInstallChaincode(n, chaincode.Chaincode, peer) 1074 } 1075 } 1076 1077 func invokeChaincodeExpectErr(n *nwo.Network, peer *nwo.Peer, command commands.ChaincodeInvoke, expectedErrMsg string) { 1078 sess, err := n.PeerUserSession(peer, "User1", command) 1079 Expect(err).NotTo(HaveOccurred()) 1080 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(1)) 1081 Expect(sess.Err).To(gbytes.Say(expectedErrMsg)) 1082 } 1083 1084 func approveChaincodeForMyOrgExpectErr(n *nwo.Network, orderer *nwo.Orderer, chaincode nwo.Chaincode, expectedErrMsg string, peers ...*nwo.Peer) { 1085 // used to ensure we only approve once per org 1086 approvedOrgs := map[string]bool{} 1087 for _, p := range peers { 1088 if _, ok := approvedOrgs[p.Organization]; !ok { 1089 sess, err := n.PeerAdminSession(p, commands.ChaincodeApproveForMyOrg{ 1090 ChannelID: channelID, 1091 Orderer: n.OrdererAddress(orderer, nwo.ListenPort), 1092 Name: chaincode.Name, 1093 Version: chaincode.Version, 1094 PackageID: chaincode.PackageID, 1095 Sequence: chaincode.Sequence, 1096 EndorsementPlugin: chaincode.EndorsementPlugin, 1097 ValidationPlugin: chaincode.ValidationPlugin, 1098 SignaturePolicy: chaincode.SignaturePolicy, 1099 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 1100 InitRequired: chaincode.InitRequired, 1101 CollectionsConfig: chaincode.CollectionsConfig, 1102 }) 1103 Expect(err).NotTo(HaveOccurred()) 1104 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 1105 approvedOrgs[p.Organization] = true 1106 Eventually(sess.Err, n.EventuallyTimeout).Should(gbytes.Say(expectedErrMsg)) 1107 } 1108 } 1109 } 1110 1111 func assertPvtdataPresencePerCollectionConfig1(n *nwo.Network, chaincodeName, marbleName string, peers ...*nwo.Peer) { 1112 if len(peers) == 0 { 1113 peers = n.Peers 1114 } 1115 for _, peer := range peers { 1116 switch peer.Organization { 1117 1118 case "Org1": 1119 marblechaincodeutil.AssertPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1120 marblechaincodeutil.AssertNotPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1121 1122 case "Org2": 1123 marblechaincodeutil.AssertPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1124 marblechaincodeutil.AssertPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1125 1126 case "Org3": 1127 marblechaincodeutil.AssertNotPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1128 marblechaincodeutil.AssertPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1129 } 1130 } 1131 } 1132 1133 func assertPvtdataPresencePerCollectionConfig2(n *nwo.Network, chaincodeName, marbleName string, peers ...*nwo.Peer) { 1134 if len(peers) == 0 { 1135 peers = n.Peers 1136 } 1137 for _, peer := range peers { 1138 switch peer.Organization { 1139 1140 case "Org1": 1141 marblechaincodeutil.AssertPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1142 marblechaincodeutil.AssertNotPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1143 1144 case "Org2", "Org3": 1145 marblechaincodeutil.AssertPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1146 marblechaincodeutil.AssertPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1147 } 1148 } 1149 } 1150 1151 func assertPvtdataPresencePerCollectionConfig7(n *nwo.Network, chaincodeName, marbleName string, excludedPeer *nwo.Peer, peers ...*nwo.Peer) { 1152 if len(peers) == 0 { 1153 peers = n.Peers 1154 } 1155 collectionMPresence := 0 1156 collectionMPDPresence := 0 1157 for _, peer := range peers { 1158 // exclude the peer that invoked originally and count number of peers disseminated to 1159 if peer != excludedPeer { 1160 switch peer.Organization { 1161 1162 case "Org1": 1163 collectionMPresence += marblechaincodeutil.CheckPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1164 marblechaincodeutil.AssertNotPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1165 1166 case "Org2": 1167 collectionMPresence += marblechaincodeutil.CheckPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1168 collectionMPDPresence += marblechaincodeutil.CheckPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1169 case "Org3": 1170 marblechaincodeutil.AssertNotPresentInCollectionM(n, channelID, chaincodeName, marbleName, peer) 1171 collectionMPDPresence += marblechaincodeutil.CheckPresentInCollectionMPD(n, channelID, chaincodeName, marbleName, peer) 1172 } 1173 } 1174 } 1175 Expect(collectionMPresence).To(Equal(1)) 1176 Expect(collectionMPDPresence).To(Equal(1)) 1177 } 1178 1179 // deliverEvent contains the response and related info from a DeliverWithPrivateData call 1180 type deliverEvent struct { 1181 BlockAndPvtData *pb.BlockAndPrivateData 1182 BlockNum uint64 1183 Err error 1184 } 1185 1186 // getEventFromDeliverService send a request to DeliverWithPrivateData grpc service 1187 // and receive the response 1188 func getEventFromDeliverService(network *nwo.Network, peer *nwo.Peer, channelID string, signingIdentity *nwo.SigningIdentity, blockNum uint64) *deliverEvent { 1189 ctx, cancelFunc1 := context.WithTimeout(context.Background(), network.EventuallyTimeout) 1190 defer cancelFunc1() 1191 eventCh, conn := registerForDeliverEvent(ctx, network, peer, channelID, signingIdentity, blockNum) 1192 defer conn.Close() 1193 event := &deliverEvent{} 1194 Eventually(eventCh, network.EventuallyTimeout).Should(Receive(event)) 1195 Expect(event.Err).NotTo(HaveOccurred()) 1196 return event 1197 } 1198 1199 func registerForDeliverEvent( 1200 ctx context.Context, 1201 network *nwo.Network, 1202 peer *nwo.Peer, 1203 channelID string, 1204 signingIdentity *nwo.SigningIdentity, 1205 blockNum uint64, 1206 ) (<-chan deliverEvent, *grpc.ClientConn) { 1207 // create a grpc.ClientConn 1208 conn := network.PeerClientConn(peer) 1209 1210 dp, err := pb.NewDeliverClient(conn).DeliverWithPrivateData(ctx) 1211 Expect(err).NotTo(HaveOccurred()) 1212 1213 // send a deliver request 1214 envelope, err := createDeliverEnvelope(channelID, signingIdentity, blockNum) 1215 Expect(err).NotTo(HaveOccurred()) 1216 err = dp.Send(envelope) 1217 Expect(err).NotTo(HaveOccurred()) 1218 err = dp.CloseSend() 1219 Expect(err).NotTo(HaveOccurred()) 1220 1221 // create a goroutine to receive the response in a separate thread 1222 eventCh := make(chan deliverEvent, 1) 1223 go receiveDeliverResponse(dp, peer, eventCh) 1224 1225 return eventCh, conn 1226 } 1227 1228 // receiveDeliverResponse expects to receive the BlockAndPrivateData response for the requested block. 1229 func receiveDeliverResponse(dp pb.Deliver_DeliverWithPrivateDataClient, peer *nwo.Peer, eventCh chan<- deliverEvent) { 1230 event := deliverEvent{} 1231 1232 resp, err := dp.Recv() 1233 if err != nil { 1234 event.Err = errors.WithMessagef(err, "error receiving deliver response from peer %s", peer.ID()) 1235 } 1236 switch r := resp.Type.(type) { 1237 case *pb.DeliverResponse_BlockAndPrivateData: 1238 event.BlockAndPvtData = r.BlockAndPrivateData 1239 event.BlockNum = r.BlockAndPrivateData.Block.Header.Number 1240 case *pb.DeliverResponse_Status: 1241 event.Err = errors.Errorf("deliver completed with status (%s) before DeliverResponse_BlockAndPrivateData received from peer %s", r.Status, peer.ID()) 1242 default: 1243 event.Err = errors.Errorf("received unexpected response type (%T) from peer %s", r, peer.ID()) 1244 } 1245 1246 select { 1247 case eventCh <- event: 1248 default: 1249 } 1250 } 1251 1252 // createDeliverEnvelope creates a deliver request based on the block number. 1253 // blockNum=0 means newest block 1254 func createDeliverEnvelope(channelID string, signingIdentity *nwo.SigningIdentity, blockNum uint64) (*cb.Envelope, error) { 1255 creator, err := signingIdentity.Serialize() 1256 if err != nil { 1257 return nil, err 1258 } 1259 header, err := createHeader(cb.HeaderType_DELIVER_SEEK_INFO, channelID, creator) 1260 if err != nil { 1261 return nil, err 1262 } 1263 1264 // if blockNum is not greater than 0, seek the newest block 1265 var seekInfo *ab.SeekInfo 1266 if blockNum > 0 { 1267 seekInfo = &ab.SeekInfo{ 1268 Start: &ab.SeekPosition{ 1269 Type: &ab.SeekPosition_Specified{ 1270 Specified: &ab.SeekSpecified{Number: blockNum}, 1271 }, 1272 }, 1273 Stop: &ab.SeekPosition{ 1274 Type: &ab.SeekPosition_Specified{ 1275 Specified: &ab.SeekSpecified{Number: blockNum}, 1276 }, 1277 }, 1278 } 1279 } else { 1280 seekInfo = &ab.SeekInfo{ 1281 Start: &ab.SeekPosition{ 1282 Type: &ab.SeekPosition_Newest{ 1283 Newest: &ab.SeekNewest{}, 1284 }, 1285 }, 1286 Stop: &ab.SeekPosition{ 1287 Type: &ab.SeekPosition_Newest{ 1288 Newest: &ab.SeekNewest{}, 1289 }, 1290 }, 1291 } 1292 } 1293 1294 // create the envelope 1295 raw := protoutil.MarshalOrPanic(seekInfo) 1296 payload := &cb.Payload{ 1297 Header: header, 1298 Data: raw, 1299 } 1300 payloadBytes := protoutil.MarshalOrPanic(payload) 1301 signature, err := signingIdentity.Sign(payloadBytes) 1302 if err != nil { 1303 return nil, err 1304 } 1305 return &cb.Envelope{ 1306 Payload: payloadBytes, 1307 Signature: signature, 1308 }, nil 1309 } 1310 1311 func createHeader(txType cb.HeaderType, channelID string, creator []byte) (*cb.Header, error) { 1312 ts, err := ptypes.TimestampProto(time.Now()) 1313 if err != nil { 1314 return nil, err 1315 } 1316 nonce, err := crypto.GetRandomNonce() 1317 if err != nil { 1318 return nil, err 1319 } 1320 chdr := &cb.ChannelHeader{ 1321 Type: int32(txType), 1322 ChannelId: channelID, 1323 TxId: protoutil.ComputeTxID(nonce, creator), 1324 Epoch: 0, 1325 Timestamp: ts, 1326 } 1327 chdrBytes := protoutil.MarshalOrPanic(chdr) 1328 1329 shdr := &cb.SignatureHeader{ 1330 Creator: creator, 1331 Nonce: nonce, 1332 } 1333 shdrBytes := protoutil.MarshalOrPanic(shdr) 1334 header := &cb.Header{ 1335 ChannelHeader: chdrBytes, 1336 SignatureHeader: shdrBytes, 1337 } 1338 return header, nil 1339 } 1340 1341 // verify collection names and pvtdataMap match expectedKVWritesMap 1342 func assertPrivateDataAsExpected(pvtdataMap map[uint64]*rwset.TxPvtReadWriteSet, expectedKVWritesMap map[string]map[string][]byte) { 1343 // In the test, each block has only 1 tx, so txSeqInBlock is 0 1344 txPvtRwset := pvtdataMap[uint64(0)] 1345 Expect(txPvtRwset.NsPvtRwset).To(HaveLen(1)) 1346 Expect(txPvtRwset.NsPvtRwset[0].Namespace).To(Equal("marblesp")) 1347 Expect(txPvtRwset.NsPvtRwset[0].CollectionPvtRwset).To(HaveLen(len(expectedKVWritesMap))) 1348 1349 // verify the collections returned in private data have expected collection names and kvRwset.Writes 1350 for _, col := range txPvtRwset.NsPvtRwset[0].CollectionPvtRwset { 1351 Expect(expectedKVWritesMap).To(HaveKey(col.CollectionName)) 1352 expectedKvWrites := expectedKVWritesMap[col.CollectionName] 1353 kvRwset := kvrwset.KVRWSet{} 1354 err := proto.Unmarshal(col.GetRwset(), &kvRwset) 1355 Expect(err).NotTo(HaveOccurred()) 1356 Expect(kvRwset.Writes).To(HaveLen(len(expectedKvWrites))) 1357 for _, kvWrite := range kvRwset.Writes { 1358 Expect(expectedKvWrites).To(HaveKey(kvWrite.Key)) 1359 Expect(kvWrite.Value).To(Equal(expectedKvWrites[kvWrite.Key])) 1360 } 1361 } 1362 } 1363 1364 func getValueForCollectionMarbles(marbleName, color, owner string, size int) []byte { 1365 marbleJSONasString := `{"docType":"marble","name":"` + marbleName + `","color":"` + color + `","size":` + strconv.Itoa(size) + `,"owner":"` + owner + `"}` 1366 return []byte(marbleJSONasString) 1367 } 1368 1369 func getValueForCollectionMarblePrivateDetails(marbleName string, price int) []byte { 1370 marbleJSONasString := `{"docType":"marblePrivateDetails","name":"` + marbleName + `","price":` + strconv.Itoa(price) + `}` 1371 return []byte(marbleJSONasString) 1372 } 1373 1374 // fetchBlocksForPeer attempts to fetch the newest block on the given peer. 1375 // It skips the orderer and returns the session's Err buffer for parsing. 1376 func fetchBlocksForPeer(n *nwo.Network, peer *nwo.Peer, user string) func() *gbytes.Buffer { 1377 return func() *gbytes.Buffer { 1378 sess, err := n.PeerUserSession(peer, user, commands.ChannelFetch{ 1379 Block: "newest", 1380 ChannelID: channelID, 1381 OutputFile: filepath.Join(n.RootDir, "newest_block.pb"), 1382 }) 1383 Expect(err).NotTo(HaveOccurred()) 1384 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 1385 return sess.Err 1386 } 1387 } 1388 1389 // updateConfigWithNewCertsForPeer updates the channel config with new certs for the designated peer 1390 func updateConfigWithNewCertsForPeer(network *nwo.Network, tempCryptoDir string, orderer *nwo.Orderer, peer *nwo.Peer) { 1391 org := network.Organization(peer.Organization) 1392 1393 By("fetching the channel policy") 1394 currentConfig := nwo.GetConfig(network, network.Peers[0], orderer, channelID) 1395 updatedConfig := proto.Clone(currentConfig).(*cb.Config) 1396 1397 By("parsing the old and new MSP configs") 1398 oldConfig := &mspp.MSPConfig{} 1399 err := proto.Unmarshal( 1400 updatedConfig.ChannelGroup.Groups["Application"].Groups[org.Name].Values["MSP"].Value, 1401 oldConfig) 1402 Expect(err).NotTo(HaveOccurred()) 1403 1404 tempOrgMSPPath := filepath.Join(tempCryptoDir, "peerOrganizations", org.Domain, "msp") 1405 newConfig, err := msp.GetVerifyingMspConfig(tempOrgMSPPath, org.MSPID, "bccsp") 1406 Expect(err).NotTo(HaveOccurred()) 1407 oldMspConfig := &mspp.FabricMSPConfig{} 1408 newMspConfig := &mspp.FabricMSPConfig{} 1409 err = proto.Unmarshal(oldConfig.Config, oldMspConfig) 1410 Expect(err).NotTo(HaveOccurred()) 1411 err = proto.Unmarshal(newConfig.Config, newMspConfig) 1412 Expect(err).NotTo(HaveOccurred()) 1413 1414 By("merging the two MSP configs") 1415 updateOldMspConfigWithNewMspConfig(oldMspConfig, newMspConfig) 1416 1417 By("updating the channel config") 1418 updatedConfig.ChannelGroup.Groups["Application"].Groups[org.Name].Values["MSP"].Value = protoutil.MarshalOrPanic( 1419 &mspp.MSPConfig{ 1420 Type: oldConfig.Type, 1421 Config: protoutil.MarshalOrPanic(oldMspConfig), 1422 }) 1423 nwo.UpdateConfig(network, orderer, channelID, currentConfig, updatedConfig, false, network.Peer(org.Name, "peer0")) 1424 } 1425 1426 // updateOldMspConfigWithNewMspConfig updates the oldMspConfig with certs from the newMspConfig 1427 func updateOldMspConfigWithNewMspConfig(oldMspConfig, newMspConfig *mspp.FabricMSPConfig) { 1428 oldMspConfig.RootCerts = append(oldMspConfig.RootCerts, newMspConfig.RootCerts...) 1429 oldMspConfig.TlsRootCerts = append(oldMspConfig.TlsRootCerts, newMspConfig.TlsRootCerts...) 1430 oldMspConfig.FabricNodeOus.PeerOuIdentifier.Certificate = nil 1431 oldMspConfig.FabricNodeOus.ClientOuIdentifier.Certificate = nil 1432 oldMspConfig.FabricNodeOus.AdminOuIdentifier.Certificate = nil 1433 } 1434 1435 // generateNewCertsForPeer generates new certs with cryptogen for the designated peer and copies 1436 // the necessary certs to the original crypto dir as well as creating an Admin2 user to use for 1437 // any peer operations involving the peer 1438 func generateNewCertsForPeer(network *nwo.Network, tempCryptoDir string, peer *nwo.Peer) { 1439 sess, err := network.Cryptogen(commands.Generate{ 1440 Config: network.CryptoConfigPath(), 1441 Output: tempCryptoDir, 1442 }) 1443 Expect(err).NotTo(HaveOccurred()) 1444 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 1445 1446 By("copying the new msp certs for the peer to the original crypto dir") 1447 oldPeerMSPPath := network.PeerLocalMSPDir(peer) 1448 org := network.Organization(peer.Organization) 1449 tempPeerMSPPath := filepath.Join( 1450 tempCryptoDir, 1451 "peerOrganizations", 1452 org.Domain, 1453 "peers", 1454 fmt.Sprintf("%s.%s", peer.Name, org.Domain), 1455 "msp", 1456 ) 1457 os.RemoveAll(oldPeerMSPPath) 1458 err = exec.Command("cp", "-r", tempPeerMSPPath, oldPeerMSPPath).Run() 1459 Expect(err).NotTo(HaveOccurred()) 1460 1461 // This lets us keep the old user certs for the org for any peers still remaining in the org 1462 // using the old certs 1463 By("copying the new Admin user cert to the original user certs dir as Admin2") 1464 oldAdminUserPath := filepath.Join( 1465 network.RootDir, 1466 "crypto", 1467 "peerOrganizations", 1468 org.Domain, 1469 "users", 1470 fmt.Sprintf("Admin2@%s", org.Domain), 1471 ) 1472 tempAdminUserPath := filepath.Join( 1473 tempCryptoDir, 1474 "peerOrganizations", 1475 org.Domain, 1476 "users", 1477 fmt.Sprintf("Admin@%s", org.Domain), 1478 ) 1479 os.RemoveAll(oldAdminUserPath) 1480 err = exec.Command("cp", "-r", tempAdminUserPath, oldAdminUserPath).Run() 1481 Expect(err).NotTo(HaveOccurred()) 1482 // We need to rename the signcert from Admin to Admin2 as well 1483 err = os.Rename( 1484 filepath.Join(oldAdminUserPath, "msp", "signcerts", fmt.Sprintf("Admin@%s-cert.pem", org.Domain)), 1485 filepath.Join(oldAdminUserPath, "msp", "signcerts", fmt.Sprintf("Admin2@%s-cert.pem", org.Domain)), 1486 ) 1487 Expect(err).NotTo(HaveOccurred()) 1488 }