github.com/hyperledger-labs/bdls@v2.1.1+incompatible/integration/gossip/gossip_test.go (about)

     1  /*
     2   *
     3   * Copyright IBM Corp. All Rights Reserved.
     4   *
     5   * SPDX-License-Identifier: Apache-2.0
     6   * /
     7   *
     8   */
     9  
    10  package gossip
    11  
    12  import (
    13  	"fmt"
    14  	"io/ioutil"
    15  	"os"
    16  	"syscall"
    17  
    18  	docker "github.com/fsouza/go-dockerclient"
    19  	"github.com/hyperledger/fabric/integration/nwo"
    20  	"github.com/hyperledger/fabric/integration/nwo/commands"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	"github.com/onsi/gomega/gbytes"
    24  	"github.com/onsi/gomega/gexec"
    25  	"github.com/tedsuo/ifrit"
    26  	"github.com/tedsuo/ifrit/ginkgomon"
    27  )
    28  
    29  var _ = Describe("Gossip Test", func() {
    30  	var (
    31  		testDir   string
    32  		client    *docker.Client
    33  		network   *nwo.Network
    34  		chaincode nwo.Chaincode
    35  	)
    36  
    37  	BeforeEach(func() {
    38  		var err error
    39  		testDir, err = ioutil.TempDir("", "e2e")
    40  		Expect(err).NotTo(HaveOccurred())
    41  
    42  		client, err = docker.NewClientFromEnv()
    43  		Expect(err).NotTo(HaveOccurred())
    44  
    45  		chaincode = nwo.Chaincode{
    46  			Name:    "mycc",
    47  			Version: "0.0",
    48  			Path:    "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
    49  			Ctor:    `{"Args":["init","a","100","b","200"]}`,
    50  			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
    51  		}
    52  	})
    53  
    54  	AfterEach(func() {
    55  		if network != nil {
    56  			network.Cleanup()
    57  		}
    58  		os.RemoveAll(testDir)
    59  	})
    60  
    61  	Describe("Gossip state transfer test", func() {
    62  		var (
    63  			ordererProcess ifrit.Process
    64  			peerProcesses  = map[string]ifrit.Process{}
    65  			peerRunners    = map[string]*ginkgomon.Runner{}
    66  		)
    67  
    68  		BeforeEach(func() {
    69  			network = nwo.New(nwo.FullSolo(), testDir, client, StartPort(), components)
    70  
    71  			network.GenerateConfigTree()
    72  			//  modify peer config
    73  			//  Org1: leader election
    74  			//  Org2: no leader election
    75  			//      peer0: follower
    76  			//      peer1: leader
    77  			for _, peer := range network.Peers {
    78  				if peer.Organization == "Org1" {
    79  					core := network.ReadPeerConfig(peer)
    80  					if peer.Name == "peer1" {
    81  						core.Peer.Gossip.Bootstrap = "127.0.0.1:21004"
    82  						network.WritePeerConfig(peer, core)
    83  					}
    84  
    85  				}
    86  				if peer.Organization == "Org2" {
    87  					core := network.ReadPeerConfig(peer)
    88  					core.Peer.Gossip.UseLeaderElection = false
    89  					if peer.Name == "peer1" {
    90  						core.Peer.Gossip.OrgLeader = true
    91  					} else {
    92  						core.Peer.Gossip.OrgLeader = false
    93  					}
    94  
    95  					network.WritePeerConfig(peer, core)
    96  				}
    97  			}
    98  			network.Bootstrap()
    99  		})
   100  
   101  		AfterEach(func() {
   102  			if ordererProcess != nil {
   103  				ordererProcess.Signal(syscall.SIGTERM)
   104  				Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
   105  			}
   106  
   107  			for _, process := range peerProcesses {
   108  				process.Signal(syscall.SIGTERM)
   109  				Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
   110  			}
   111  		})
   112  
   113  		It("syncs blocks from the peer if no orderer is available, using solo network with 2 orgs, 2 peers each", func() {
   114  			orderer := network.Orderer("orderer")
   115  			ordererRunner := network.OrdererRunner(orderer)
   116  			ordererProcess = ifrit.Invoke(ordererRunner)
   117  			Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())
   118  
   119  			peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
   120  			peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")
   121  
   122  			By("bring up all four peers")
   123  			peersToBringUp := []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2}
   124  			startPeers(network, peersToBringUp, peerProcesses, peerRunners, false)
   125  
   126  			channelName := "testchannel"
   127  			network.CreateChannel(channelName, orderer, peer0Org1)
   128  			By("join all peers to channel")
   129  			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)
   130  
   131  			network.UpdateChannelAnchors(orderer, channelName)
   132  
   133  			// base peer will be used for chaincode interactions
   134  			basePeerForTransactions := peer0Org1
   135  			nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, basePeerForTransactions)
   136  
   137  			By("STATE TRANSFER TEST 1: newly joined peers should receive blocks from the peers that are already up")
   138  
   139  			// Note, a better test would be to bring orderer down before joining the two peers.
   140  			// However, network.JoinChannel() requires orderer to be up so that genesis block can be fetched from orderer before joining peers.
   141  			// Therefore, for now we've joined all four peers and stop the two peers that should be synced up.
   142  			peersToStop := []*nwo.Peer{peer1Org1, peer1Org2}
   143  			stopPeers(network, peersToStop, peerProcesses)
   144  
   145  			By("confirm peer0Org1 elected to be a leader")
   146  			expectedMsg := "Elected as a leader, starting delivery service for channel testchannel"
   147  			Eventually(peerRunners[peer0Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))
   148  
   149  			peersToSyncUp := []*nwo.Peer{peer1Org1, peer1Org2}
   150  			sendTransactionsAndSyncUpPeers(network, orderer, basePeerForTransactions, peersToSyncUp, channelName, &ordererProcess, ordererRunner, peerProcesses, peerRunners)
   151  
   152  			By("STATE TRANSFER TEST 2: restarted peers should receive blocks from the peers that are already up")
   153  			basePeerForTransactions = peer1Org1
   154  			nwo.InstallChaincodeLegacy(network, chaincode, basePeerForTransactions)
   155  
   156  			By("stop peer0Org1 (currently elected leader in Org1) and peer1Org2 (static leader in Org2)")
   157  			peersToStop = []*nwo.Peer{peer0Org1, peer1Org2}
   158  			stopPeers(network, peersToStop, peerProcesses)
   159  
   160  			By("confirm peer1Org1 elected to be a leader")
   161  			Eventually(peerRunners[peer1Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))
   162  
   163  			peersToSyncUp = []*nwo.Peer{peer0Org1, peer1Org2}
   164  			// Note that with the static leader in Org2 down, the static follower peer0Org2 will also get blocks via state transfer
   165  			// This effectively tests leader election as well, since the newly elected leader in Org1 (peer1Org1) will be the only peer
   166  			// that receives blocks from orderer and will therefore serve as the provider of blocks to all other peers.
   167  			sendTransactionsAndSyncUpPeers(network, orderer, basePeerForTransactions, peersToSyncUp, channelName, &ordererProcess, ordererRunner, peerProcesses, peerRunners)
   168  
   169  		})
   170  
   171  	})
   172  })
   173  
   174  func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) {
   175  	for i := 0; i < 5; i++ {
   176  		sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{
   177  			ChannelID: channelID,
   178  			Orderer:   n.OrdererAddress(orderer, nwo.ListenPort),
   179  			Name:      chaincodeName,
   180  			Ctor:      `{"Args":["invoke","a","b","10"]}`,
   181  			PeerAddresses: []string{
   182  				n.PeerAddress(peer, nwo.ListenPort),
   183  			},
   184  			WaitForEvent: true,
   185  		})
   186  		Expect(err).NotTo(HaveOccurred())
   187  		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
   188  		Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
   189  	}
   190  }
   191  
   192  func startPeers(network *nwo.Network, peersToStart []*nwo.Peer, peerProc map[string]ifrit.Process, peerRun map[string]*ginkgomon.Runner, forceStateTransfer bool) {
   193  
   194  	env := []string{fmt.Sprint("FABRIC_LOGGING_SPEC=info:gossip.state=debug")}
   195  
   196  	// Setting CORE_PEER_GOSSIP_STATE_CHECKINTERVAL to 200ms (from default of 10s) will ensure that state transfer happens quickly,
   197  	// before blocks are gossipped through normal mechanisms
   198  	if forceStateTransfer {
   199  		env = append(env, fmt.Sprint("CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms"))
   200  	}
   201  
   202  	for _, peer := range peersToStart {
   203  		runner := network.PeerRunner(peer, env...)
   204  		process := ifrit.Invoke(runner)
   205  		Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
   206  
   207  		peerProc[peer.ID()] = process
   208  		peerRun[peer.ID()] = runner
   209  	}
   210  }
   211  
   212  func stopPeers(network *nwo.Network, peersToStop []*nwo.Peer, peerProcesses map[string]ifrit.Process) {
   213  	for _, peer := range peersToStop {
   214  		id := peer.ID()
   215  		proc := peerProcesses[id]
   216  		proc.Signal(syscall.SIGTERM)
   217  		Eventually(proc.Wait(), network.EventuallyTimeout).Should(Receive())
   218  		delete(peerProcesses, id)
   219  	}
   220  }
   221  
   222  func assertPeersLedgerHeight(n *nwo.Network, orderer *nwo.Orderer, peersToSyncUp []*nwo.Peer, expectedVal int, channelID string) {
   223  	for _, peer := range peersToSyncUp {
   224  		Eventually(func() int {
   225  			return nwo.GetLedgerHeight(n, peer, channelID)
   226  		}, n.EventuallyTimeout).Should(Equal(expectedVal))
   227  	}
   228  }
   229  
   230  // send transactions, stop orderering server, then start peers to ensure they received blcoks via state transfer
   231  func sendTransactionsAndSyncUpPeers(network *nwo.Network, orderer *nwo.Orderer, basePeer *nwo.Peer, peersToSyncUp []*nwo.Peer, channelName string,
   232  	ordererProcess *ifrit.Process, ordererRunner *ginkgomon.Runner,
   233  	peerProcesses map[string]ifrit.Process, peerRunners map[string]*ginkgomon.Runner) {
   234  
   235  	By("create transactions")
   236  	runTransactions(network, orderer, basePeer, "mycc", channelName)
   237  	basePeerLedgerHeight := nwo.GetLedgerHeight(network, basePeer, channelName)
   238  
   239  	By("stop orderer")
   240  	(*ordererProcess).Signal(syscall.SIGTERM)
   241  	Eventually((*ordererProcess).Wait(), network.EventuallyTimeout).Should(Receive())
   242  	*ordererProcess = nil
   243  
   244  	By("start the peers contained in the peersToSyncUp list")
   245  	startPeers(network, peersToSyncUp, peerProcesses, peerRunners, true)
   246  
   247  	By("ensure the peers are synced up")
   248  	assertPeersLedgerHeight(network, orderer, peersToSyncUp, basePeerLedgerHeight, channelName)
   249  
   250  	By("restart orderer")
   251  	orderer = network.Orderer("orderer")
   252  	ordererRunner = network.OrdererRunner(orderer)
   253  	*ordererProcess = ifrit.Invoke(ordererRunner)
   254  	Eventually((*ordererProcess).Ready(), network.EventuallyTimeout).Should(BeClosed())
   255  }