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