github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/ledger/reset_rollback_test.go (about)

     1  /*
     2  Copyright hechain All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package ledger
     8  
     9  import (
    10  	"encoding/base64"
    11  	"encoding/json"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  	"syscall"
    18  
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  
    22  	docker "github.com/fsouza/go-dockerclient"
    23  	"github.com/hechain20/hechain/integration/nwo"
    24  	"github.com/hechain20/hechain/integration/nwo/commands"
    25  	"github.com/hyperledger/fabric-protos-go/common"
    26  	"github.com/onsi/gomega/gbytes"
    27  	"github.com/onsi/gomega/gexec"
    28  	"github.com/tedsuo/ifrit"
    29  )
    30  
    31  var _ = Describe("rollback, reset, pause, resume, and unjoin peer node commands", func() {
    32  	// at the beginning of each test under this block, we have defined two collections:
    33  	// 1. collectionMarbles - Org1 and Org2 have access to this collection
    34  	// 2. collectionMarblePrivateDetails - Org2 and Org3 have access to this collection
    35  	// when calling QueryChaincode with first arg "readMarble", it will query collectionMarbles[1]
    36  	// when calling QueryChaincode with first arg "readMarblePrivateDetails", it will query collectionMarblePrivateDetails[2]
    37  	var (
    38  		setup  *setup
    39  		helper *testHelper
    40  	)
    41  
    42  	BeforeEach(func() {
    43  		setup = initThreeOrgsSetup()
    44  		nwo.EnableCapabilities(setup.network, setup.channelID, "Application", "V2_0", setup.orderer, setup.peers...)
    45  		helper = &testHelper{
    46  			networkHelper: &networkHelper{
    47  				Network:   setup.network,
    48  				orderer:   setup.orderer,
    49  				peers:     setup.peers,
    50  				testDir:   setup.testDir,
    51  				channelID: setup.channelID,
    52  			},
    53  		}
    54  
    55  		By("installing and instantiating chaincode on all peers")
    56  		chaincode := nwo.Chaincode{
    57  			Name:              "marblesp",
    58  			Version:           "1.0",
    59  			Path:              components.Build("github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd"),
    60  			Lang:              "binary",
    61  			PackageFile:       filepath.Join(setup.testDir, "marbles-pvtdata.tar.gz"),
    62  			Label:             "marbles-private-20",
    63  			SignaturePolicy:   `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member')`,
    64  			CollectionsConfig: filepath.Join("testdata", "collection_configs", "collections_config1.json"),
    65  			Sequence:          "1",
    66  		}
    67  
    68  		helper.deployChaincode(chaincode)
    69  
    70  		org2peer0 := setup.network.Peer("Org2", "peer0")
    71  		height := helper.getLedgerHeight(org2peer0)
    72  
    73  		By("creating 5 blocks")
    74  		for i := 1; i <= 5; i++ {
    75  			helper.addMarble("marblesp", fmt.Sprintf(`{"name":"marble%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), org2peer0)
    76  			helper.waitUntilAllPeersEqualLedgerHeight(height + i)
    77  		}
    78  
    79  		By("verifying marble1 to marble5 exist in collectionMarbles & collectionMarblePrivateDetails in Org2.peer0")
    80  		for i := 1; i <= 5; i++ {
    81  			helper.assertPresentInCollectionM("marblesp", fmt.Sprintf("marble%d", i), org2peer0)
    82  			helper.assertPresentInCollectionMPD("marblesp", fmt.Sprintf("marble%d", i), org2peer0)
    83  		}
    84  	})
    85  
    86  	AfterEach(func() {
    87  		setup.cleanup()
    88  	})
    89  
    90  	// This test executes the rollback, reset, pause, and resume commands on the following peerss
    91  	// Org1.peer0 - rollback
    92  	// Org2.peer0 - reset
    93  	// Org3.peer0 - pause/rollback/resume
    94  	//
    95  	// There are 14 blocks created in BeforeEach (before rollback/reset).
    96  	// block 0: genesis, block 1: org1Anchor, block 2: org2Anchor, block 3: org3Anchor
    97  	// block 4 to 8: chaincode instantiation, block 9 to 13: chaincode invoke to add marbles.
    98  	It("pauses and resumes channels and rolls back and resets the ledger", func() {
    99  		By("Checking ledger height on each peer")
   100  		for _, peer := range helper.peers {
   101  			Expect(helper.getLedgerHeight(peer)).Should(Equal(14))
   102  		}
   103  
   104  		org1peer0 := setup.network.Peer("Org1", "peer0")
   105  		org2peer0 := setup.network.Peer("Org2", "peer0")
   106  		org3peer0 := setup.network.Peer("Org3", "peer0")
   107  
   108  		// Negative test: rollback, reset, pause, and resume should fail when the peer is online
   109  		expectedErrMessage := "as another peer node command is executing," +
   110  			" wait for that command to complete its execution or terminate it before retrying"
   111  		By("Rolling back the peer to block 6 from block 13 while the peer node is online")
   112  		helper.rollback(org1peer0, 6, expectedErrMessage, false)
   113  		By("Resetting the peer to the genesis block while the peer node is online")
   114  		helper.reset(org2peer0, expectedErrMessage, false)
   115  		By("Pausing the peer while the peer node is online")
   116  		helper.pause(org3peer0, expectedErrMessage, false)
   117  		By("Resuming the peer while the peer node is online")
   118  		helper.resume(org3peer0, expectedErrMessage, false)
   119  
   120  		By("Stopping the network to test commands")
   121  		setup.terminateAllProcess()
   122  
   123  		By("Rolling back the channel to block 6 from block 14 on org1peer0")
   124  		helper.rollback(org1peer0, 6, "", true)
   125  
   126  		By("Resetting org2peer0 to the genesis block")
   127  		helper.reset(org2peer0, "", true)
   128  
   129  		By("Pausing the channel on org3peer0")
   130  		helper.pause(org3peer0, "", true)
   131  
   132  		By("Rolling back the paused channel to block 6 from block 14 on org3peer0")
   133  		helper.rollback(org3peer0, 6, "", true)
   134  
   135  		By("Verifying paused channel is not found upon peer restart")
   136  		setup.startPeer(org3peer0)
   137  		helper.assertPausedChannel(org3peer0)
   138  
   139  		By("Checking preResetHeightFile exists for a paused channel that is also rolled back or reset")
   140  		setup.startBrokerAndOrderer()
   141  		preResetHeightFile := filepath.Join(setup.network.PeerLedgerDir(org3peer0), "chains/chains", helper.channelID, "__preResetHeight")
   142  		Expect(preResetHeightFile).To(BeARegularFile())
   143  
   144  		setup.terminateAllProcess()
   145  
   146  		By("Resuming the peer")
   147  		helper.resume(org3peer0, "", true)
   148  
   149  		By("Verifying that the endorsement is disabled when the peer has not received missing blocks")
   150  		setup.startPeers()
   151  		for _, peer := range setup.peers {
   152  			helper.assertDisabledEndorser("marblesp", peer)
   153  		}
   154  
   155  		By("Bringing the peers to recent height by starting the orderer")
   156  		setup.startBrokerAndOrderer()
   157  		for _, peer := range setup.peers {
   158  			By("Verifying endorsement is enabled and preResetHeightFile is removed on peer " + peer.ID())
   159  			helper.waitUntilEndorserEnabled(peer)
   160  			preResetHeightFile := filepath.Join(setup.network.PeerLedgerDir(peer), "chains/chains", helper.channelID, "__preResetHeight")
   161  			Expect(preResetHeightFile).NotTo(BeAnExistingFile())
   162  		}
   163  
   164  		setup.network.VerifyMembership(setup.peers, setup.channelID, "marblesp")
   165  
   166  		By("Verifying leger height on all peers")
   167  		helper.waitUntilAllPeersEqualLedgerHeight(14)
   168  
   169  		// Test chaincode works correctly after the commands
   170  		By("Creating 2 more blocks post rollback/reset")
   171  		for i := 6; i <= 7; i++ {
   172  			helper.addMarble("marblesp", fmt.Sprintf(`{"name":"marble%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), org2peer0)
   173  			helper.waitUntilAllPeersEqualLedgerHeight(14 + i - 5)
   174  		}
   175  
   176  		By("Verifying marble1 to marble7 exist in collectionMarbles & collectionMarblePrivateDetails on org2peer0")
   177  		for i := 1; i <= 7; i++ {
   178  			helper.assertPresentInCollectionM("marblesp", fmt.Sprintf("marble%d", i), org2peer0)
   179  			helper.assertPresentInCollectionMPD("marblesp", fmt.Sprintf("marble%d", i), org2peer0)
   180  		}
   181  
   182  		// statedb rebuild test
   183  		By("Stopping peers and deleting the statedb folder on peer Org2.peer0")
   184  		peer := setup.network.Peer("Org2", "peer0")
   185  		setup.stopPeers()
   186  		dbPath := filepath.Join(setup.network.PeerLedgerDir(peer), "stateLeveldb")
   187  		Expect(os.RemoveAll(dbPath)).NotTo(HaveOccurred())
   188  		Expect(dbPath).NotTo(BeADirectory())
   189  		By("Restarting the peer Org2.peer0")
   190  		setup.startPeer(peer)
   191  		Expect(dbPath).To(BeADirectory())
   192  		helper.assertPresentInCollectionM("marblesp", "marble2", peer)
   193  	})
   194  
   195  	// This test exercises peer node unjoin on the following peers:
   196  	// Org1.peer0 - unjoin
   197  	// Org2.peer0 -
   198  	// Org3.peer0 - unjoin (via partial / resumed deletion on restart)
   199  	It("unjoins channels and checks side effects on the ledger and transient storage", func() {
   200  		By("Checking ledger heights on each peer")
   201  		for _, peer := range helper.peers {
   202  			Expect(helper.getLedgerHeight(peer)).Should(Equal(14))
   203  		}
   204  
   205  		org1peer0 := setup.network.Peer("Org1", "peer0")
   206  		org2peer0 := setup.network.Peer("Org2", "peer0")
   207  		org3peer0 := setup.network.Peer("Org3", "peer0")
   208  
   209  		// Negative test: peer node unjoin should fail when the peer is online.
   210  		By("unjoining the peer while the peer node is online")
   211  		expectedErrMessage := "as another peer node command is executing," +
   212  			" wait for that command to complete its execution or terminate it before retrying"
   213  		helper.unjoin(org1peer0, expectedErrMessage, false)
   214  		helper.unjoin(org2peer0, expectedErrMessage, false)
   215  		helper.unjoin(org3peer0, expectedErrMessage, false)
   216  
   217  		By("stopping the peers to test unjoin commands")
   218  		setup.stopPeers()
   219  
   220  		By("Unjoining from a channel while the peer is down")
   221  		helper.unjoin(org1peer0, "", true)
   222  
   223  		// Negative test: unjoin when the channel has been unjoined
   224  		By("Double unjoining from a channel")
   225  		expectedErrMessage = "unjoin channel \\[testchannel\\]: cannot update ledger status, ledger \\[testchannel\\] does not exist"
   226  		helper.unjoin(org1peer0, expectedErrMessage, false)
   227  
   228  		// Simulate an error in peer unjoin by marking the ledger folder as read-only.
   229  		By("Unjoining from a peer with a read-only ledger file system")
   230  		ledgerStoragePath := filepath.Join(setup.network.PeerLedgerDir(org3peer0), "chains/chains", helper.channelID)
   231  		Expect(os.Chmod(ledgerStoragePath, 0o555)).NotTo(HaveOccurred())
   232  		Expect(os.RemoveAll(ledgerStoragePath)).To(HaveOccurred()) // can not delete write-only ledger folder
   233  		expectedErrMessage = "ledgersData/chains/chains/testchannel/blockfile_000000: permission denied"
   234  		helper.unjoin(org3peer0, expectedErrMessage, false)
   235  		Expect(os.Chmod(ledgerStoragePath, 0o755)).NotTo(HaveOccurred())
   236  
   237  		By("restarting peers")
   238  		setup.startPeer(org1peer0)
   239  		setup.startPeer(org2peer0)
   240  		setup.startPeer(org3peer0)
   241  
   242  		helper.assertUnjoinedChannel(org1peer0)
   243  		helper.assertUnjoinedChannel(org3peer0)
   244  
   245  		By("rejoining the channel with org1")
   246  		setup.network.JoinChannel(helper.channelID, setup.orderer, org1peer0)
   247  		helper.waitUntilPeerEqualLedgerHeight(org1peer0, 14)
   248  
   249  		By("Creating 2 more blocks post re-join org1")
   250  		for i := 6; i <= 7; i++ {
   251  			helper.addMarble("marblesp", fmt.Sprintf(`{"name":"marble%d", "color":"blue", "size":35, "owner":"tom", "price":99}`, i), org1peer0)
   252  			helper.waitUntilPeerEqualLedgerHeight(org1peer0, 14+i-5)
   253  			helper.waitUntilPeerEqualLedgerHeight(org2peer0, 14+i-5)
   254  		}
   255  	})
   256  })
   257  
   258  type setup struct {
   259  	testDir        string
   260  	channelID      string
   261  	network        *nwo.Network
   262  	peers          []*nwo.Peer
   263  	peerProcess    []ifrit.Process
   264  	orderer        *nwo.Orderer
   265  	ordererProcess ifrit.Process
   266  	brokerProcess  ifrit.Process
   267  }
   268  
   269  func initThreeOrgsSetup() *setup {
   270  	var err error
   271  	testDir, err := ioutil.TempDir("", "reset-rollback")
   272  	Expect(err).NotTo(HaveOccurred())
   273  
   274  	client, err := docker.NewClientFromEnv()
   275  	Expect(err).NotTo(HaveOccurred())
   276  
   277  	n := nwo.New(nwo.ThreeOrgSolo(), testDir, client, StartPort(), components)
   278  	n.GenerateConfigTree()
   279  	n.Bootstrap()
   280  
   281  	peers := []*nwo.Peer{
   282  		n.Peer("Org1", "peer0"),
   283  		n.Peer("Org2", "peer0"),
   284  		n.Peer("Org3", "peer0"),
   285  	}
   286  
   287  	setup := &setup{
   288  		testDir:   testDir,
   289  		network:   n,
   290  		peers:     peers,
   291  		channelID: "testchannel",
   292  	}
   293  
   294  	setup.startBrokerAndOrderer()
   295  
   296  	setup.startPeer(peers[0])
   297  	setup.startPeer(peers[1])
   298  	setup.startPeer(peers[2])
   299  
   300  	orderer := n.Orderer("orderer")
   301  	n.CreateAndJoinChannel(orderer, "testchannel")
   302  	n.UpdateChannelAnchors(orderer, "testchannel")
   303  	setup.orderer = orderer
   304  
   305  	By("verifying membership")
   306  	setup.network.VerifyMembership(setup.peers, setup.channelID)
   307  
   308  	return setup
   309  }
   310  
   311  func (s *setup) cleanup() {
   312  	s.terminateAllProcess()
   313  	s.network.Cleanup()
   314  	os.RemoveAll(s.testDir)
   315  }
   316  
   317  func (s *setup) terminateAllProcess() {
   318  	s.ordererProcess.Signal(syscall.SIGTERM)
   319  	Eventually(s.ordererProcess.Wait(), s.network.EventuallyTimeout).Should(Receive())
   320  	s.ordererProcess = nil
   321  
   322  	s.brokerProcess.Signal(syscall.SIGTERM)
   323  	Eventually(s.brokerProcess.Wait(), s.network.EventuallyTimeout).Should(Receive())
   324  	s.brokerProcess = nil
   325  
   326  	for _, p := range s.peerProcess {
   327  		p.Signal(syscall.SIGTERM)
   328  		Eventually(p.Wait(), s.network.EventuallyTimeout).Should(Receive())
   329  	}
   330  	s.peerProcess = nil
   331  }
   332  
   333  func (s *setup) startPeers() {
   334  	for _, peer := range s.peers {
   335  		s.startPeer(peer)
   336  	}
   337  }
   338  
   339  func (s *setup) stopPeers() {
   340  	for _, p := range s.peerProcess {
   341  		p.Signal(syscall.SIGTERM)
   342  		Eventually(p.Wait(), s.network.EventuallyTimeout).Should(Receive())
   343  	}
   344  	s.peerProcess = nil
   345  }
   346  
   347  func (s *setup) startPeer(peer *nwo.Peer) {
   348  	peerRunner := s.network.PeerRunner(peer)
   349  	peerProcess := ifrit.Invoke(peerRunner)
   350  	Eventually(peerProcess.Ready(), s.network.EventuallyTimeout).Should(BeClosed())
   351  	s.peerProcess = append(s.peerProcess, peerProcess)
   352  }
   353  
   354  func (s *setup) startBrokerAndOrderer() {
   355  	brokerRunner := s.network.BrokerGroupRunner()
   356  	brokerProcess := ifrit.Invoke(brokerRunner)
   357  	Eventually(brokerProcess.Ready(), s.network.EventuallyTimeout).Should(BeClosed())
   358  	s.brokerProcess = brokerProcess
   359  
   360  	ordererRunner := s.network.OrdererGroupRunner()
   361  	ordererProcess := ifrit.Invoke(ordererRunner)
   362  	Eventually(ordererProcess.Ready(), s.network.EventuallyTimeout).Should(BeClosed())
   363  	s.ordererProcess = ordererProcess
   364  }
   365  
   366  type networkHelper struct {
   367  	*nwo.Network
   368  	orderer   *nwo.Orderer
   369  	peers     []*nwo.Peer
   370  	channelID string
   371  	testDir   string
   372  }
   373  
   374  func (nh *networkHelper) deployChaincode(chaincode nwo.Chaincode) {
   375  	nwo.DeployChaincode(nh.Network, nh.channelID, nh.orderer, chaincode)
   376  	nh.waitUntilAllPeersEqualLedgerHeight(nh.getLedgerHeight(nh.peers[0]))
   377  }
   378  
   379  func (nh *networkHelper) waitUntilAllPeersEqualLedgerHeight(height int) {
   380  	for _, peer := range nh.peers {
   381  		nh.waitUntilPeerEqualLedgerHeight(peer, height)
   382  	}
   383  }
   384  
   385  func (nh *networkHelper) waitUntilPeerEqualLedgerHeight(peer *nwo.Peer, height int) {
   386  	Eventually(func() int {
   387  		return nh.getLedgerHeight(peer)
   388  	}, nh.EventuallyTimeout).Should(Equal(height))
   389  }
   390  
   391  func (nh *networkHelper) getLedgerHeight(peer *nwo.Peer) int {
   392  	sess, err := nh.PeerUserSession(peer, "User1", commands.ChannelInfo{
   393  		ChannelID: nh.channelID,
   394  	})
   395  	Expect(err).NotTo(HaveOccurred())
   396  	Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   397  
   398  	channelInfoStr := strings.TrimPrefix(string(sess.Buffer().Contents()[:]), "Blockchain info:")
   399  	channelInfo := common.BlockchainInfo{}
   400  	err = json.Unmarshal([]byte(channelInfoStr), &channelInfo)
   401  	Expect(err).NotTo(HaveOccurred())
   402  	return int(channelInfo.Height)
   403  }
   404  
   405  func (nh *networkHelper) queryChaincode(peer *nwo.Peer, command commands.ChaincodeQuery, expectedMessage string, expectSuccess bool) {
   406  	sess, err := nh.PeerUserSession(peer, "User1", command)
   407  	Expect(err).NotTo(HaveOccurred())
   408  	if expectSuccess {
   409  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   410  		Expect(sess).To(gbytes.Say(expectedMessage))
   411  	} else {
   412  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   413  		Expect(sess.Err).To(gbytes.Say(expectedMessage))
   414  	}
   415  }
   416  
   417  func (nh *networkHelper) invokeChaincode(peer *nwo.Peer, command commands.ChaincodeInvoke) {
   418  	sess, err := nh.PeerUserSession(peer, "User1", command)
   419  	Expect(err).NotTo(HaveOccurred())
   420  	Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   421  	Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful."))
   422  }
   423  
   424  func (nh *networkHelper) rollback(peer *nwo.Peer, blockNumber int, expectedErrMessage string, expectSuccess bool) {
   425  	rollbackCmd := commands.NodeRollback{ChannelID: nh.channelID, BlockNumber: blockNumber}
   426  	sess, err := nh.PeerUserSession(peer, "User1", rollbackCmd)
   427  	Expect(err).NotTo(HaveOccurred())
   428  	if expectSuccess {
   429  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   430  	} else {
   431  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   432  		Expect(sess.Err).To(gbytes.Say(expectedErrMessage))
   433  	}
   434  }
   435  
   436  func (nh *networkHelper) reset(peer *nwo.Peer, expectedErrMessage string, expectSuccess bool) {
   437  	resetCmd := commands.NodeReset{}
   438  	sess, err := nh.PeerUserSession(peer, "User1", resetCmd)
   439  	Expect(err).NotTo(HaveOccurred())
   440  	if expectSuccess {
   441  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   442  	} else {
   443  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   444  		Expect(sess.Err).To(gbytes.Say(expectedErrMessage))
   445  	}
   446  }
   447  
   448  func (nh *networkHelper) pause(peer *nwo.Peer, expectedErrMessage string, expectSuccess bool) {
   449  	pauseCmd := commands.NodePause{ChannelID: nh.channelID}
   450  	sess, err := nh.PeerUserSession(peer, "User1", pauseCmd)
   451  	Expect(err).NotTo(HaveOccurred())
   452  	if expectSuccess {
   453  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   454  	} else {
   455  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   456  		Expect(sess.Err).To(gbytes.Say(expectedErrMessage))
   457  	}
   458  }
   459  
   460  func (nh *networkHelper) resume(peer *nwo.Peer, expectedErrMessage string, expectSuccess bool) {
   461  	resumeCmd := commands.NodeResume{ChannelID: nh.channelID}
   462  	sess, err := nh.PeerUserSession(peer, "User1", resumeCmd)
   463  	Expect(err).NotTo(HaveOccurred())
   464  	if expectSuccess {
   465  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   466  	} else {
   467  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   468  		Expect(sess.Err).To(gbytes.Say(expectedErrMessage))
   469  	}
   470  }
   471  
   472  func (nh *networkHelper) unjoin(peer *nwo.Peer, expectedErrMessage string, expectSuccess bool) {
   473  	unjoinCmd := commands.NodeUnjoin{ChannelID: nh.channelID}
   474  	sess, err := nh.PeerUserSession(peer, "User1", unjoinCmd)
   475  	Expect(err).NotTo(HaveOccurred())
   476  	if expectSuccess {
   477  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(0))
   478  	} else {
   479  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit(1))
   480  		Expect(sess.Err).To(gbytes.Say(expectedErrMessage))
   481  	}
   482  }
   483  
   484  func (nh *networkHelper) waitUntilEndorserEnabled(peer *nwo.Peer) {
   485  	Eventually(func() *gbytes.Buffer {
   486  		sess, err := nh.PeerUserSession(peer, "User1", commands.ChannelInfo{
   487  			ChannelID: nh.channelID,
   488  		})
   489  		Expect(err).NotTo(HaveOccurred())
   490  		Eventually(sess, nh.EventuallyTimeout).Should(gexec.Exit())
   491  		return sess.Buffer()
   492  	}, nh.EventuallyTimeout).Should(gbytes.Say("Blockchain info"))
   493  }
   494  
   495  type testHelper struct {
   496  	*networkHelper
   497  }
   498  
   499  func (th *testHelper) addMarble(chaincodeName, marbleDetails string, peer *nwo.Peer) {
   500  	marbleDetailsBase64 := base64.StdEncoding.EncodeToString([]byte(marbleDetails))
   501  
   502  	command := commands.ChaincodeInvoke{
   503  		ChannelID: th.channelID,
   504  		Orderer:   th.OrdererAddress(th.orderer, nwo.ListenPort),
   505  		Name:      chaincodeName,
   506  		Ctor:      `{"Args":["initMarble"]}`,
   507  		Transient: fmt.Sprintf(`{"marble":"%s"}`, marbleDetailsBase64),
   508  		PeerAddresses: []string{
   509  			th.PeerAddress(peer, nwo.ListenPort),
   510  		},
   511  		WaitForEvent: true,
   512  	}
   513  	th.invokeChaincode(peer, command)
   514  }
   515  
   516  // assertPresentInCollectionM asserts that the private data for given marble is present in collection
   517  // 'readMarble' at the given peers
   518  func (th *testHelper) assertPresentInCollectionM(chaincodeName, marbleName string, peerList ...*nwo.Peer) {
   519  	command := commands.ChaincodeQuery{
   520  		ChannelID: th.channelID,
   521  		Name:      chaincodeName,
   522  		Ctor:      fmt.Sprintf(`{"Args":["readMarble","%s"]}`, marbleName),
   523  	}
   524  	expectedMsg := fmt.Sprintf(`{"docType":"marble","name":"%s"`, marbleName)
   525  	for _, peer := range peerList {
   526  		th.queryChaincode(peer, command, expectedMsg, true)
   527  	}
   528  }
   529  
   530  // assertPresentInCollectionMPD asserts that the private data for given marble is present
   531  // in collection 'readMarblePrivateDetails' at the given peers
   532  func (th *testHelper) assertPresentInCollectionMPD(chaincodeName, marbleName string, peerList ...*nwo.Peer) {
   533  	command := commands.ChaincodeQuery{
   534  		ChannelID: th.channelID,
   535  		Name:      chaincodeName,
   536  		Ctor:      fmt.Sprintf(`{"Args":["readMarblePrivateDetails","%s"]}`, marbleName),
   537  	}
   538  	expectedMsg := fmt.Sprintf(`{"docType":"marblePrivateDetails","name":"%s"`, marbleName)
   539  	for _, peer := range peerList {
   540  		th.queryChaincode(peer, command, expectedMsg, true)
   541  	}
   542  }
   543  
   544  func (th *testHelper) assertDisabledEndorser(chaincodeName string, peer *nwo.Peer) {
   545  	command := commands.ChaincodeQuery{
   546  		ChannelID: th.channelID,
   547  		Name:      chaincodeName,
   548  		Ctor:      `{"Args":["readMarble","marble1"]}`,
   549  	}
   550  	expectedMsg := "endorse requests are blocked while ledgers are being rebuilt"
   551  	th.queryChaincode(peer, command, expectedMsg, false)
   552  }
   553  
   554  func (th *testHelper) assertPausedChannel(peer *nwo.Peer) {
   555  	sess, err := th.PeerUserSession(peer, "User1", commands.ChannelInfo{
   556  		ChannelID: th.channelID,
   557  	})
   558  	Expect(err).NotTo(HaveOccurred())
   559  	Eventually(sess, th.EventuallyTimeout).Should(gexec.Exit(1))
   560  	Expect(sess.Err).To(gbytes.Say("Invalid chain ID"))
   561  }
   562  
   563  func (th *testHelper) assertUnjoinedChannel(peer *nwo.Peer) {
   564  	sess, err := th.PeerUserSession(peer, "User1", commands.ChannelInfo{
   565  		ChannelID: th.channelID,
   566  	})
   567  	Expect(err).NotTo(HaveOccurred())
   568  	Eventually(sess, th.EventuallyTimeout).Should(gexec.Exit(1))
   569  	Expect(sess.Err).To(gbytes.Say("Invalid chain ID"))
   570  
   571  	channelLedgerDir := filepath.Join(th.Network.PeerLedgerDir(peer), "chains/chains", th.channelID)
   572  	Expect(channelLedgerDir).NotTo(BeADirectory())
   573  }