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

     1  /*
     2   * Copyright hechain. All Rights Reserved.
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   */
     6  
     7  package gossip
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"syscall"
    14  	"time"
    15  
    16  	docker "github.com/fsouza/go-dockerclient"
    17  	"github.com/hechain20/hechain/integration/nwo"
    18  	"github.com/hechain20/hechain/integration/nwo/commands"
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  	"github.com/onsi/gomega/gbytes"
    22  	"github.com/onsi/gomega/gexec"
    23  	"github.com/tedsuo/ifrit"
    24  	"github.com/tedsuo/ifrit/ginkgomon"
    25  )
    26  
    27  var _ = Describe("Gossip State Transfer and Membership", func() {
    28  	var (
    29  		testDir     string
    30  		network     *nwo.Network
    31  		nwprocs     *networkProcesses
    32  		chaincode   nwo.Chaincode
    33  		channelName string
    34  	)
    35  
    36  	BeforeEach(func() {
    37  		var err error
    38  		testDir, err = ioutil.TempDir("", "gossip-statexfer")
    39  		Expect(err).NotTo(HaveOccurred())
    40  
    41  		dockerClient, err := docker.NewClientFromEnv()
    42  		Expect(err).NotTo(HaveOccurred())
    43  
    44  		channelName = "testchannel"
    45  		network = nwo.New(nwo.FullSolo(), testDir, dockerClient, StartPort(), components)
    46  		network.GenerateConfigTree()
    47  
    48  		nwprocs = &networkProcesses{
    49  			network:       network,
    50  			peerRunners:   map[string]*ginkgomon.Runner{},
    51  			peerProcesses: map[string]ifrit.Process{},
    52  		}
    53  
    54  		chaincode = nwo.Chaincode{
    55  			Name:    "mycc",
    56  			Version: "0.0",
    57  			Path:    "github.com/hechain20/hechain/integration/chaincode/simple/cmd",
    58  			Ctor:    `{"Args":["init","a","100","b","200"]}`,
    59  			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
    60  		}
    61  	})
    62  
    63  	AfterEach(func() {
    64  		if nwprocs != nil {
    65  			nwprocs.terminateAll()
    66  		}
    67  		if network != nil {
    68  			network.Cleanup()
    69  		}
    70  		os.RemoveAll(testDir)
    71  	})
    72  
    73  	It("syncs blocks from the peer via state transfer when no orderer is available", func() {
    74  		//  modify peer config to enable state transfer on all peers, and configure leaders as follows:
    75  		//  Org1: leader election
    76  		//  Org2: no leader election
    77  		//      peer0: follower
    78  		//      peer1: leader
    79  		for _, peer := range network.Peers {
    80  			if peer.Organization == "Org1" {
    81  				if peer.Name == "peer0" {
    82  					core := network.ReadPeerConfig(peer)
    83  					core.Peer.Gossip.State.Enabled = true
    84  					core.Peer.Gossip.UseLeaderElection = true
    85  					core.Peer.Gossip.OrgLeader = false
    86  					network.WritePeerConfig(peer, core)
    87  				}
    88  				if peer.Name == "peer1" {
    89  					core := network.ReadPeerConfig(peer)
    90  					core.Peer.Gossip.State.Enabled = true
    91  					core.Peer.Gossip.UseLeaderElection = true
    92  					core.Peer.Gossip.OrgLeader = false
    93  					core.Peer.Gossip.Bootstrap = fmt.Sprintf("127.0.0.1:%d", network.ReservePort())
    94  					network.WritePeerConfig(peer, core)
    95  				}
    96  			}
    97  			if peer.Organization == "Org2" {
    98  				core := network.ReadPeerConfig(peer)
    99  				core.Peer.Gossip.State.Enabled = true
   100  				core.Peer.Gossip.UseLeaderElection = false
   101  				core.Peer.Gossip.OrgLeader = peer.Name == "peer1"
   102  				network.WritePeerConfig(peer, core)
   103  			}
   104  		}
   105  
   106  		network.Bootstrap()
   107  		orderer := network.Orderer("orderer")
   108  		nwprocs.ordererRunner = network.OrdererRunner(orderer)
   109  		nwprocs.ordererProcess = ifrit.Invoke(nwprocs.ordererRunner)
   110  		Eventually(nwprocs.ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())
   111  
   112  		peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
   113  		peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")
   114  
   115  		By("bringing up all four peers")
   116  		startPeers(nwprocs, false, peer0Org1, peer1Org1, peer0Org2, peer1Org2)
   117  
   118  		network.CreateChannel(channelName, orderer, peer0Org1)
   119  		By("joining all peers to channel")
   120  		network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)
   121  
   122  		network.UpdateChannelAnchors(orderer, channelName)
   123  
   124  		// base peer will be used for chaincode interactions
   125  		basePeerForTransactions := peer0Org1
   126  		nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, basePeerForTransactions)
   127  
   128  		By("verifying peer0Org1 discovers all the peers and the legacy chaincode before starting the tests")
   129  		Eventually(nwo.DiscoverPeers(network, peer0Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   130  			network.DiscoveredPeer(peer0Org1, "_lifecycle", "mycc"),
   131  			network.DiscoveredPeer(peer1Org1, "_lifecycle"),
   132  			network.DiscoveredPeer(peer0Org2, "_lifecycle"),
   133  			network.DiscoveredPeer(peer1Org2, "_lifecycle"),
   134  		))
   135  
   136  		By("STATE TRANSFER TEST 1: newly joined peers should receive blocks from the peers that are already up")
   137  
   138  		// Note, a better test would be to bring orderer down before joining the two peers.
   139  		// However, network.JoinChannel() requires orderer to be up so that genesis block can be fetched from orderer before joining peers.
   140  		// Therefore, for now we've joined all four peers and stop the two peers that should be synced up.
   141  		stopPeers(nwprocs, peer1Org1, peer1Org2)
   142  
   143  		By("confirming peer0Org1 was elected to be a leader")
   144  		expectedMsg := "Elected as a leader, starting delivery service for channel testchannel"
   145  		Eventually(nwprocs.peerRunners[peer0Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))
   146  
   147  		sendTransactionsAndSyncUpPeers(nwprocs, orderer, basePeerForTransactions, channelName, peer1Org1, peer1Org2)
   148  
   149  		By("STATE TRANSFER TEST 2: restarted peers should receive blocks from the peers that are already up")
   150  		basePeerForTransactions = peer1Org1
   151  		nwo.InstallChaincodeLegacy(network, chaincode, basePeerForTransactions)
   152  
   153  		By("verifying peer0Org1 discovers all the peers and the additional legacy chaincode installed on peer1Org1")
   154  		Eventually(nwo.DiscoverPeers(network, peer0Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   155  			network.DiscoveredPeer(peer0Org1, "_lifecycle", "mycc"),
   156  			network.DiscoveredPeer(peer1Org1, "_lifecycle", "mycc"),
   157  			network.DiscoveredPeer(peer0Org2, "_lifecycle"),
   158  			network.DiscoveredPeer(peer1Org2, "_lifecycle"),
   159  		))
   160  
   161  		By("stopping peer0Org1 (currently elected leader in Org1) and peer1Org2 (static leader in Org2)")
   162  		stopPeers(nwprocs, peer0Org1, peer1Org2)
   163  
   164  		By("confirming peer1Org1 was elected to be a leader")
   165  		Eventually(nwprocs.peerRunners[peer1Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))
   166  
   167  		// Note that with the static leader in Org2 down, the static follower peer0Org2 will also get blocks via state transfer
   168  		// This effectively tests leader election as well, since the newly elected leader in Org1 (peer1Org1) will be the only peer
   169  		// that receives blocks from orderer and will therefore serve as the provider of blocks to all other peers.
   170  		sendTransactionsAndSyncUpPeers(nwprocs, orderer, basePeerForTransactions, channelName, peer0Org1, peer1Org2)
   171  
   172  		By("verifying peer0Org1 can still discover all the peers and the legacy chaincode after it has been restarted")
   173  		Eventually(nwo.DiscoverPeers(network, peer0Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   174  			network.DiscoveredPeer(peer0Org1, "_lifecycle", "mycc"),
   175  			network.DiscoveredPeer(peer1Org1, "_lifecycle", "mycc"),
   176  			network.DiscoveredPeer(peer0Org2, "_lifecycle"),
   177  			network.DiscoveredPeer(peer1Org2, "_lifecycle"),
   178  		))
   179  	})
   180  
   181  	When("gossip connection is lost and restored", func() {
   182  		var (
   183  			orderer       *nwo.Orderer
   184  			peerEndpoints map[string]string = map[string]string{}
   185  		)
   186  
   187  		BeforeEach(func() {
   188  			//  modify peer config
   189  			for _, peer := range network.Peers {
   190  				core := network.ReadPeerConfig(peer)
   191  				core.Peer.Gossip.AliveTimeInterval = 1 * time.Second
   192  				core.Peer.Gossip.AliveExpirationTimeout = 2 * core.Peer.Gossip.AliveTimeInterval
   193  				core.Peer.Gossip.ReconnectInterval = 2 * time.Second
   194  				core.Peer.Gossip.MsgExpirationFactor = 2
   195  				core.Peer.Gossip.MaxConnectionAttempts = 10
   196  				network.WritePeerConfig(peer, core)
   197  				peerEndpoints[peer.ID()] = core.Peer.Address
   198  			}
   199  
   200  			network.Bootstrap()
   201  			orderer = network.Orderer("orderer")
   202  			nwprocs.ordererRunner = network.OrdererRunner(orderer)
   203  			nwprocs.ordererProcess = ifrit.Invoke(nwprocs.ordererRunner)
   204  			Eventually(nwprocs.ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())
   205  		})
   206  
   207  		It("updates membership when peers in the same org are stopped and restarted", func() {
   208  			peer0Org1 := network.Peer("Org1", "peer0")
   209  			peer1Org1 := network.Peer("Org1", "peer1")
   210  
   211  			By("bringing up all peers")
   212  			startPeers(nwprocs, false, peer0Org1, peer1Org1)
   213  
   214  			By("creating and joining a channel")
   215  			network.CreateChannel(channelName, orderer, peer0Org1)
   216  			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1)
   217  			network.UpdateChannelAnchors(orderer, channelName)
   218  
   219  			By("verifying peer1Org1 discovers all the peers before testing membership change on it")
   220  			Eventually(nwo.DiscoverPeers(network, peer1Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   221  				network.DiscoveredPeer(peer0Org1, "_lifecycle"),
   222  				network.DiscoveredPeer(peer1Org1, "_lifecycle"),
   223  			))
   224  
   225  			By("verifying membership change on peer1Org1 when an anchor peer in the same org is stopped and restarted")
   226  			expectedMsgFromExpirationCallback := fmt.Sprintf("Do not remove bootstrap or anchor peer endpoint %s from membership", peerEndpoints[peer0Org1.ID()])
   227  			assertPeerMembershipUpdate(network, peer1Org1, []*nwo.Peer{peer0Org1}, nwprocs, expectedMsgFromExpirationCallback)
   228  
   229  			By("verifying peer0Org1 discovers all the peers before testing membership change on it")
   230  			Eventually(nwo.DiscoverPeers(network, peer0Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   231  				network.DiscoveredPeer(peer0Org1, "_lifecycle"),
   232  				network.DiscoveredPeer(peer1Org1, "_lifecycle"),
   233  			))
   234  
   235  			By("verifying membership change on peer0Org1 when a non-anchor peer in the same org is stopped and restarted")
   236  			expectedMsgFromExpirationCallback = fmt.Sprintf("Removing member: Endpoint: %s", peerEndpoints[peer1Org1.ID()])
   237  			assertPeerMembershipUpdate(network, peer0Org1, []*nwo.Peer{peer1Org1}, nwprocs, expectedMsgFromExpirationCallback)
   238  		})
   239  
   240  		It("updates peer membership when peers in another org are stopped and restarted", func() {
   241  			peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
   242  			peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")
   243  
   244  			By("bringing up all peers")
   245  			startPeers(nwprocs, false, peer0Org1, peer1Org1, peer0Org2, peer1Org2)
   246  
   247  			By("creating and joining a channel")
   248  			network.CreateChannel(channelName, orderer, peer0Org1)
   249  			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)
   250  			network.UpdateChannelAnchors(orderer, channelName)
   251  
   252  			By("verifying membership on peer1Org1")
   253  			Eventually(nwo.DiscoverPeers(network, peer1Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf(
   254  				network.DiscoveredPeer(peer0Org1, "_lifecycle"),
   255  				network.DiscoveredPeer(peer1Org1, "_lifecycle"),
   256  				network.DiscoveredPeer(peer0Org2, "_lifecycle"),
   257  				network.DiscoveredPeer(peer1Org2, "_lifecycle"),
   258  			))
   259  
   260  			By("stopping anchor peer peer0Org1 to have only one peer in org1")
   261  			stopPeers(nwprocs, peer0Org1)
   262  
   263  			By("verifying peer membership update when peers in another org are stopped and restarted")
   264  			expectedMsgFromExpirationCallback := fmt.Sprintf("Do not remove bootstrap or anchor peer endpoint %s from membership", peerEndpoints[peer0Org2.ID()])
   265  			assertPeerMembershipUpdate(network, peer1Org1, []*nwo.Peer{peer0Org2, peer1Org2}, nwprocs, expectedMsgFromExpirationCallback)
   266  		})
   267  	})
   268  })
   269  
   270  func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) {
   271  	for i := 0; i < 5; i++ {
   272  		sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{
   273  			ChannelID: channelID,
   274  			Orderer:   n.OrdererAddress(orderer, nwo.ListenPort),
   275  			Name:      chaincodeName,
   276  			Ctor:      `{"Args":["invoke","a","b","10"]}`,
   277  			PeerAddresses: []string{
   278  				n.PeerAddress(peer, nwo.ListenPort),
   279  			},
   280  			WaitForEvent: true,
   281  		})
   282  		Expect(err).NotTo(HaveOccurred())
   283  		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
   284  		Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
   285  	}
   286  }
   287  
   288  // networkProcesses holds references to the network, its runners, and processes.
   289  type networkProcesses struct {
   290  	network *nwo.Network
   291  
   292  	ordererRunner  *ginkgomon.Runner
   293  	ordererProcess ifrit.Process
   294  
   295  	peerRunners   map[string]*ginkgomon.Runner
   296  	peerProcesses map[string]ifrit.Process
   297  }
   298  
   299  func (n *networkProcesses) terminateAll() {
   300  	if n.ordererProcess != nil {
   301  		n.ordererProcess.Signal(syscall.SIGTERM)
   302  		Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive())
   303  	}
   304  	for _, process := range n.peerProcesses {
   305  		process.Signal(syscall.SIGTERM)
   306  		Eventually(process.Wait(), n.network.EventuallyTimeout).Should(Receive())
   307  	}
   308  }
   309  
   310  func startPeers(n *networkProcesses, forceStateTransfer bool, peersToStart ...*nwo.Peer) {
   311  	env := []string{"FABRIC_LOGGING_SPEC=info:gossip.state=debug:gossip.discovery=debug"}
   312  
   313  	// Setting CORE_PEER_GOSSIP_STATE_CHECKINTERVAL to 200ms (from default of 10s) will ensure that state transfer happens quickly,
   314  	// before blocks are gossipped through normal mechanisms
   315  	if forceStateTransfer {
   316  		env = append(env, "CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms")
   317  	}
   318  
   319  	for _, peer := range peersToStart {
   320  		runner := n.network.PeerRunner(peer, env...)
   321  		process := ifrit.Invoke(runner)
   322  		Eventually(process.Ready(), n.network.EventuallyTimeout).Should(BeClosed())
   323  
   324  		n.peerProcesses[peer.ID()] = process
   325  		n.peerRunners[peer.ID()] = runner
   326  	}
   327  }
   328  
   329  func stopPeers(n *networkProcesses, peersToStop ...*nwo.Peer) {
   330  	for _, peer := range peersToStop {
   331  		id := peer.ID()
   332  		proc := n.peerProcesses[id]
   333  		proc.Signal(syscall.SIGTERM)
   334  		Eventually(proc.Wait(), n.network.EventuallyTimeout).Should(Receive())
   335  		delete(n.peerProcesses, id)
   336  	}
   337  }
   338  
   339  func assertPeersLedgerHeight(n *nwo.Network, peersToSyncUp []*nwo.Peer, expectedVal int, channelID string) {
   340  	for _, peer := range peersToSyncUp {
   341  		Eventually(func() int {
   342  			return nwo.GetLedgerHeight(n, peer, channelID)
   343  		}, n.EventuallyTimeout).Should(Equal(expectedVal))
   344  	}
   345  }
   346  
   347  // send transactions, stop orderering server, then start peers to ensure they received blcoks via state transfer
   348  func sendTransactionsAndSyncUpPeers(n *networkProcesses, orderer *nwo.Orderer, basePeer *nwo.Peer, channelName string, peersToSyncUp ...*nwo.Peer) {
   349  	By("creating transactions")
   350  	runTransactions(n.network, orderer, basePeer, "mycc", channelName)
   351  	basePeerLedgerHeight := nwo.GetLedgerHeight(n.network, basePeer, channelName)
   352  
   353  	By("stopping orderer")
   354  	n.ordererProcess.Signal(syscall.SIGTERM)
   355  	Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive())
   356  	n.ordererProcess = nil
   357  
   358  	By("starting the peers contained in the peersToSyncUp list")
   359  	startPeers(n, true, peersToSyncUp...)
   360  
   361  	By("ensuring the peers are synced up")
   362  	assertPeersLedgerHeight(n.network, peersToSyncUp, basePeerLedgerHeight, channelName)
   363  
   364  	By("restarting orderer")
   365  	n.ordererRunner = n.network.OrdererRunner(orderer)
   366  	n.ordererProcess = ifrit.Invoke(n.ordererRunner)
   367  	Eventually(n.ordererProcess.Ready(), n.network.EventuallyTimeout).Should(BeClosed())
   368  }
   369  
   370  // assertPeerMembershipUpdate stops and restart peersToRestart and verify peer membership
   371  func assertPeerMembershipUpdate(network *nwo.Network, peer *nwo.Peer, peersToRestart []*nwo.Peer, nwprocs *networkProcesses, expectedMsgFromExpirationCallback string) {
   372  	stopPeers(nwprocs, peersToRestart...)
   373  
   374  	// timeout is the same amount of time as it takes to remove a message from the aliveMsgStore, and add a second as buffer
   375  	core := network.ReadPeerConfig(peer)
   376  	timeout := core.Peer.Gossip.AliveExpirationTimeout*time.Duration(core.Peer.Gossip.MsgExpirationFactor) + time.Second
   377  	By("verifying peer membership after all other peers are stopped")
   378  	Eventually(nwo.DiscoverPeers(network, peer, "User1", "testchannel"), timeout, 100*time.Millisecond).Should(ConsistOf(
   379  		network.DiscoveredPeer(peer, "_lifecycle"),
   380  	))
   381  
   382  	By("verifying expected log message from expiration callback")
   383  	runner := nwprocs.peerRunners[peer.ID()]
   384  	Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsgFromExpirationCallback))
   385  
   386  	By("restarting peers")
   387  	startPeers(nwprocs, false, peersToRestart...)
   388  
   389  	By("verifying peer membership, expected to discover restarted peers")
   390  	expectedPeers := make([]nwo.DiscoveredPeer, len(peersToRestart)+1)
   391  	expectedPeers[0] = network.DiscoveredPeer(peer, "_lifecycle")
   392  	for i, p := range peersToRestart {
   393  		expectedPeers[i+1] = network.DiscoveredPeer(p, "_lifecycle")
   394  	}
   395  	timeout = 3 * core.Peer.Gossip.ReconnectInterval
   396  	Eventually(nwo.DiscoverPeers(network, peer, "User1", "testchannel"), timeout, 100*time.Millisecond).Should(ConsistOf(expectedPeers))
   397  }