github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/integration/gossip/gossip_test.go (about) 1 /* 2 * Copyright IBM Corp. 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/osdi23p228/fabric/integration/nwo" 18 "github.com/osdi23p228/fabric/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/osdi23p228/fabric/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 182 When("gossip connection is lost and restored", func() { 183 var ( 184 orderer *nwo.Orderer 185 peerEndpoints map[string]string = map[string]string{} 186 ) 187 188 BeforeEach(func() { 189 // modify peer config 190 for _, peer := range network.Peers { 191 core := network.ReadPeerConfig(peer) 192 core.Peer.Gossip.AliveTimeInterval = 1 * time.Second 193 core.Peer.Gossip.AliveExpirationTimeout = 2 * core.Peer.Gossip.AliveTimeInterval 194 core.Peer.Gossip.ReconnectInterval = 2 * time.Second 195 core.Peer.Gossip.MsgExpirationFactor = 2 196 core.Peer.Gossip.MaxConnectionAttempts = 10 197 network.WritePeerConfig(peer, core) 198 peerEndpoints[peer.ID()] = core.Peer.Address 199 } 200 201 network.Bootstrap() 202 orderer = network.Orderer("orderer") 203 nwprocs.ordererRunner = network.OrdererRunner(orderer) 204 nwprocs.ordererProcess = ifrit.Invoke(nwprocs.ordererRunner) 205 Eventually(nwprocs.ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed()) 206 }) 207 208 It("updates membership when peers in the same org are stopped and restarted", func() { 209 peer0Org1 := network.Peer("Org1", "peer0") 210 peer1Org1 := network.Peer("Org1", "peer1") 211 212 By("bringing up all peers") 213 startPeers(nwprocs, false, peer0Org1, peer1Org1) 214 215 By("creating and joining a channel") 216 network.CreateChannel(channelName, orderer, peer0Org1) 217 network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1) 218 network.UpdateChannelAnchors(orderer, channelName) 219 220 By("verifying peer1Org1 discovers all the peers before testing membership change on it") 221 Eventually(nwo.DiscoverPeers(network, peer1Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf( 222 network.DiscoveredPeer(peer0Org1, "_lifecycle"), 223 network.DiscoveredPeer(peer1Org1, "_lifecycle"), 224 )) 225 226 By("verifying membership change on peer1Org1 when an anchor peer in the same org is stopped and restarted") 227 expectedMsgFromExpirationCallback := fmt.Sprintf("Do not remove bootstrap or anchor peer endpoint %s from membership", peerEndpoints[peer0Org1.ID()]) 228 assertPeerMembershipUpdate(network, peer1Org1, []*nwo.Peer{peer0Org1}, nwprocs, expectedMsgFromExpirationCallback) 229 230 By("verifying peer0Org1 discovers all the peers before testing membership change on it") 231 Eventually(nwo.DiscoverPeers(network, peer0Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf( 232 network.DiscoveredPeer(peer0Org1, "_lifecycle"), 233 network.DiscoveredPeer(peer1Org1, "_lifecycle"), 234 )) 235 236 By("verifying membership change on peer0Org1 when a non-anchor peer in the same org is stopped and restarted") 237 expectedMsgFromExpirationCallback = fmt.Sprintf("Removing member: Endpoint: %s", peerEndpoints[peer1Org1.ID()]) 238 assertPeerMembershipUpdate(network, peer0Org1, []*nwo.Peer{peer1Org1}, nwprocs, expectedMsgFromExpirationCallback) 239 }) 240 241 It("updates peer membership when peers in another org are stopped and restarted", func() { 242 peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1") 243 peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1") 244 245 By("bringing up all peers") 246 startPeers(nwprocs, false, peer0Org1, peer1Org1, peer0Org2, peer1Org2) 247 248 By("creating and joining a channel") 249 network.CreateChannel(channelName, orderer, peer0Org1) 250 network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2) 251 network.UpdateChannelAnchors(orderer, channelName) 252 253 By("verifying membership on peer1Org1") 254 Eventually(nwo.DiscoverPeers(network, peer1Org1, "User1", "testchannel"), network.EventuallyTimeout).Should(ConsistOf( 255 network.DiscoveredPeer(peer0Org1, "_lifecycle"), 256 network.DiscoveredPeer(peer1Org1, "_lifecycle"), 257 network.DiscoveredPeer(peer0Org2, "_lifecycle"), 258 network.DiscoveredPeer(peer1Org2, "_lifecycle"), 259 )) 260 261 By("stopping anchor peer peer0Org1 to have only one peer in org1") 262 stopPeers(nwprocs, peer0Org1) 263 264 By("verifying peer membership update when peers in another org are stopped and restarted") 265 expectedMsgFromExpirationCallback := fmt.Sprintf("Do not remove bootstrap or anchor peer endpoint %s from membership", peerEndpoints[peer0Org2.ID()]) 266 assertPeerMembershipUpdate(network, peer1Org1, []*nwo.Peer{peer0Org2, peer1Org2}, nwprocs, expectedMsgFromExpirationCallback) 267 }) 268 }) 269 }) 270 271 func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) { 272 for i := 0; i < 5; i++ { 273 sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{ 274 ChannelID: channelID, 275 Orderer: n.OrdererAddress(orderer, nwo.ListenPort), 276 Name: chaincodeName, 277 Ctor: `{"Args":["invoke","a","b","10"]}`, 278 PeerAddresses: []string{ 279 n.PeerAddress(peer, nwo.ListenPort), 280 }, 281 WaitForEvent: true, 282 }) 283 Expect(err).NotTo(HaveOccurred()) 284 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 285 Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200")) 286 } 287 } 288 289 // networkProcesses holds references to the network, its runners, and processes. 290 type networkProcesses struct { 291 network *nwo.Network 292 293 ordererRunner *ginkgomon.Runner 294 ordererProcess ifrit.Process 295 296 peerRunners map[string]*ginkgomon.Runner 297 peerProcesses map[string]ifrit.Process 298 } 299 300 func (n *networkProcesses) terminateAll() { 301 if n.ordererProcess != nil { 302 n.ordererProcess.Signal(syscall.SIGTERM) 303 Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive()) 304 } 305 for _, process := range n.peerProcesses { 306 process.Signal(syscall.SIGTERM) 307 Eventually(process.Wait(), n.network.EventuallyTimeout).Should(Receive()) 308 } 309 } 310 311 func startPeers(n *networkProcesses, forceStateTransfer bool, peersToStart ...*nwo.Peer) { 312 env := []string{"FABRIC_LOGGING_SPEC=info:gossip.state=debug:gossip.discovery=debug"} 313 314 // Setting CORE_PEER_GOSSIP_STATE_CHECKINTERVAL to 200ms (from default of 10s) will ensure that state transfer happens quickly, 315 // before blocks are gossipped through normal mechanisms 316 if forceStateTransfer { 317 env = append(env, "CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms") 318 } 319 320 for _, peer := range peersToStart { 321 runner := n.network.PeerRunner(peer, env...) 322 process := ifrit.Invoke(runner) 323 Eventually(process.Ready(), n.network.EventuallyTimeout).Should(BeClosed()) 324 325 n.peerProcesses[peer.ID()] = process 326 n.peerRunners[peer.ID()] = runner 327 } 328 } 329 330 func stopPeers(n *networkProcesses, peersToStop ...*nwo.Peer) { 331 for _, peer := range peersToStop { 332 id := peer.ID() 333 proc := n.peerProcesses[id] 334 proc.Signal(syscall.SIGTERM) 335 Eventually(proc.Wait(), n.network.EventuallyTimeout).Should(Receive()) 336 delete(n.peerProcesses, id) 337 } 338 } 339 340 func assertPeersLedgerHeight(n *nwo.Network, peersToSyncUp []*nwo.Peer, expectedVal int, channelID string) { 341 for _, peer := range peersToSyncUp { 342 Eventually(func() int { 343 return nwo.GetLedgerHeight(n, peer, channelID) 344 }, n.EventuallyTimeout).Should(Equal(expectedVal)) 345 } 346 } 347 348 // send transactions, stop orderering server, then start peers to ensure they received blcoks via state transfer 349 func sendTransactionsAndSyncUpPeers(n *networkProcesses, orderer *nwo.Orderer, basePeer *nwo.Peer, channelName string, peersToSyncUp ...*nwo.Peer) { 350 By("creating transactions") 351 runTransactions(n.network, orderer, basePeer, "mycc", channelName) 352 basePeerLedgerHeight := nwo.GetLedgerHeight(n.network, basePeer, channelName) 353 354 By("stopping orderer") 355 n.ordererProcess.Signal(syscall.SIGTERM) 356 Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive()) 357 n.ordererProcess = nil 358 359 By("starting the peers contained in the peersToSyncUp list") 360 startPeers(n, true, peersToSyncUp...) 361 362 By("ensuring the peers are synced up") 363 assertPeersLedgerHeight(n.network, peersToSyncUp, basePeerLedgerHeight, channelName) 364 365 By("restarting orderer") 366 n.ordererRunner = n.network.OrdererRunner(orderer) 367 n.ordererProcess = ifrit.Invoke(n.ordererRunner) 368 Eventually(n.ordererProcess.Ready(), n.network.EventuallyTimeout).Should(BeClosed()) 369 } 370 371 // assertPeerMembershipUpdate stops and restart peersToRestart and verify peer membership 372 func assertPeerMembershipUpdate(network *nwo.Network, peer *nwo.Peer, peersToRestart []*nwo.Peer, nwprocs *networkProcesses, expectedMsgFromExpirationCallback string) { 373 stopPeers(nwprocs, peersToRestart...) 374 375 // timeout is the same amount of time as it takes to remove a message from the aliveMsgStore, and add a second as buffer 376 core := network.ReadPeerConfig(peer) 377 timeout := core.Peer.Gossip.AliveExpirationTimeout*time.Duration(core.Peer.Gossip.MsgExpirationFactor) + time.Second 378 By("verifying peer membership after all other peers are stopped") 379 Eventually(nwo.DiscoverPeers(network, peer, "User1", "testchannel"), timeout, 100*time.Millisecond).Should(ConsistOf( 380 network.DiscoveredPeer(peer, "_lifecycle"), 381 )) 382 383 By("verifying expected log message from expiration callback") 384 runner := nwprocs.peerRunners[peer.ID()] 385 Eventually(runner.Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsgFromExpirationCallback)) 386 387 By("restarting peers") 388 startPeers(nwprocs, false, peersToRestart...) 389 390 By("verifying peer membership, expected to discover restarted peers") 391 expectedPeers := make([]nwo.DiscoveredPeer, len(peersToRestart)+1) 392 expectedPeers[0] = network.DiscoveredPeer(peer, "_lifecycle") 393 for i, p := range peersToRestart { 394 expectedPeers[i+1] = network.DiscoveredPeer(p, "_lifecycle") 395 } 396 timeout = 3 * core.Peer.Gossip.ReconnectInterval 397 Eventually(nwo.DiscoverPeers(network, peer, "User1", "testchannel"), timeout, 100*time.Millisecond).Should(ConsistOf(expectedPeers)) 398 }