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