github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/integration/raft/config_test.go (about)

     1  /*
     2  Copyright IBM Corp All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package raft
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  	"sync"
    17  	"syscall"
    18  	"time"
    19  
    20  	docker "github.com/fsouza/go-dockerclient"
    21  	"github.com/golang/protobuf/proto"
    22  	"github.com/hyperledger/fabric-protos-go/common"
    23  	"github.com/hyperledger/fabric-protos-go/msp"
    24  	protosorderer "github.com/hyperledger/fabric-protos-go/orderer"
    25  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    26  	"github.com/hyperledger/fabric/integration/nwo"
    27  	"github.com/hyperledger/fabric/integration/nwo/commands"
    28  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    29  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    30  	"github.com/hyperledger/fabric/protoutil"
    31  	. "github.com/onsi/ginkgo"
    32  	. "github.com/onsi/gomega"
    33  	"github.com/onsi/gomega/gbytes"
    34  	"github.com/onsi/gomega/gexec"
    35  	"github.com/tedsuo/ifrit"
    36  	"github.com/tedsuo/ifrit/ginkgomon"
    37  )
    38  
    39  var _ = Describe("EndToEnd reconfiguration and onboarding", func() {
    40  	var (
    41  		testDir string
    42  		client  *docker.Client
    43  		network *nwo.Network
    44  		peer    *nwo.Peer
    45  
    46  		networkProcess   ifrit.Process
    47  		ordererProcesses []ifrit.Process
    48  		ordererRunners   []*ginkgomon.Runner
    49  	)
    50  
    51  	BeforeEach(func() {
    52  		ordererRunners = nil
    53  		ordererProcesses = nil
    54  
    55  		var err error
    56  		testDir, err = ioutil.TempDir("", "e2e-etcfraft_reconfig")
    57  		Expect(err).NotTo(HaveOccurred())
    58  
    59  		client, err = docker.NewClientFromEnv()
    60  		Expect(err).NotTo(HaveOccurred())
    61  	})
    62  
    63  	AfterEach(func() {
    64  		if networkProcess != nil {
    65  			networkProcess.Signal(syscall.SIGTERM)
    66  			Eventually(networkProcess.Wait(), network.EventuallyTimeout).Should(Receive())
    67  		}
    68  		if network != nil {
    69  			network.Cleanup()
    70  		}
    71  		for _, ordererInstance := range ordererProcesses {
    72  			ordererInstance.Signal(syscall.SIGTERM)
    73  			Eventually(ordererInstance.Wait(), network.EventuallyTimeout).Should(Receive())
    74  		}
    75  		os.RemoveAll(testDir)
    76  	})
    77  
    78  	Describe("three node etcdraft network with 2 orgs", func() {
    79  		BeforeEach(func() {
    80  			network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components)
    81  			network.GenerateConfigTree()
    82  			network.Bootstrap()
    83  
    84  			networkRunner := network.NetworkGroupRunner()
    85  			networkProcess = ifrit.Invoke(networkRunner)
    86  			Eventually(networkProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())
    87  		})
    88  
    89  		// This tests:
    90  		//
    91  		// 1. channel creation with raft orderer,
    92  		// 2. all the nodes on three-node raft cluster are in sync wrt blocks,
    93  		// 3. raft orderer processes type A config updates and delivers the
    94  		//    config blocks to the peers.
    95  		It("executes an etcdraft network with 2 orgs and three orderer nodes", func() {
    96  			orderer1 := network.Orderer("orderer1")
    97  			orderer2 := network.Orderer("orderer2")
    98  			orderer3 := network.Orderer("orderer3")
    99  			peer := network.Peer("Org1", "peer1")
   100  			org1Peer0 := network.Peer("Org1", "peer0")
   101  			blockFile1 := filepath.Join(testDir, "newest_orderer1_block.pb")
   102  			blockFile2 := filepath.Join(testDir, "newest_orderer2_block.pb")
   103  			blockFile3 := filepath.Join(testDir, "newest_orderer3_block.pb")
   104  
   105  			By("Ordering service system channel is ready")
   106  			assertBlockReception(map[string]int{
   107  				"systemchannel": 0,
   108  			}, []*nwo.Orderer{orderer1, orderer2, orderer3}, peer, network)
   109  
   110  			fetchLatestBlock := func(targetOrderer *nwo.Orderer, blockFile string) {
   111  				c := commands.ChannelFetch{
   112  					ChannelID:  "testchannel",
   113  					Block:      "newest",
   114  					OutputFile: blockFile,
   115  				}
   116  				if targetOrderer != nil {
   117  					c.Orderer = network.OrdererAddress(targetOrderer, nwo.ListenPort)
   118  				}
   119  				sess, err := network.PeerAdminSession(org1Peer0, c)
   120  				Expect(err).NotTo(HaveOccurred())
   121  				Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
   122  			}
   123  
   124  			By("Creating a new channel")
   125  			network.CreateChannel("testchannel", orderer1, peer)
   126  
   127  			// the above can work even if the orderer nodes are not in the same Raft
   128  			// cluster; we need to verify all the three orderer nodes are in sync wrt
   129  			// blocks.
   130  			By("Fetching the latest blocks from all the orderer nodes and testing them for equality")
   131  			fetchLatestBlock(orderer1, blockFile1)
   132  			fetchLatestBlock(orderer2, blockFile2)
   133  			fetchLatestBlock(orderer3, blockFile3)
   134  			b1 := nwo.UnmarshalBlockFromFile(blockFile1)
   135  			b2 := nwo.UnmarshalBlockFromFile(blockFile2)
   136  			b3 := nwo.UnmarshalBlockFromFile(blockFile3)
   137  			Expect(protoutil.BlockHeaderBytes(b1.Header)).To(Equal(protoutil.BlockHeaderBytes(b2.Header)))
   138  			Expect(protoutil.BlockHeaderBytes(b2.Header)).To(Equal(protoutil.BlockHeaderBytes(b3.Header)))
   139  		})
   140  	})
   141  
   142  	Describe("Invalid Raft config metadata", func() {
   143  		It("refuses to start orderer or rejects config update", func() {
   144  			By("Creating malformed genesis block")
   145  			network = nwo.New(nwo.BasicEtcdRaft(), testDir, client, StartPort(), components)
   146  			network.GenerateConfigTree()
   147  			network.Bootstrap()
   148  
   149  			sysProfile := genesisconfig.Load(network.SystemChannel.Profile, network.RootDir)
   150  			Expect(sysProfile.Orderer).NotTo(BeNil())
   151  			sysProfile.Orderer.EtcdRaft.Options.ElectionTick = sysProfile.Orderer.EtcdRaft.Options.HeartbeatTick
   152  			pgen := encoder.New(sysProfile)
   153  			genesisBlock := pgen.GenesisBlockForChannel(network.SystemChannel.Name)
   154  			data, err := proto.Marshal(genesisBlock)
   155  			Expect(err).NotTo(HaveOccurred())
   156  			ioutil.WriteFile(network.OutputBlockPath(network.SystemChannel.Name), data, 0644)
   157  
   158  			By("Starting orderer with malformed genesis block")
   159  			ordererRunner := network.OrdererGroupRunner()
   160  			process := ifrit.Invoke(ordererRunner)
   161  			Eventually(process.Wait, network.EventuallyTimeout).Should(Receive()) // orderer process should exit
   162  			os.RemoveAll(testDir)
   163  
   164  			By("Starting orderer with correct genesis block")
   165  			testDir, err = ioutil.TempDir("", "e2e")
   166  			Expect(err).NotTo(HaveOccurred())
   167  			network = nwo.New(nwo.BasicEtcdRaft(), testDir, client, StartPort(), components)
   168  			network.GenerateConfigTree()
   169  			network.Bootstrap()
   170  
   171  			orderer := network.Orderer("orderer")
   172  			runner := network.OrdererRunner(orderer)
   173  			process = ifrit.Invoke(runner)
   174  			Eventually(process.Ready, network.EventuallyTimeout).Should(BeClosed())
   175  			defer func() {
   176  				process.Signal(syscall.SIGTERM)
   177  				Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
   178  			}()
   179  
   180  			By("Waiting for system channel to be ready")
   181  			findLeader([]*ginkgomon.Runner{runner})
   182  
   183  			By("Creating malformed channel creation config tx")
   184  			channel := "testchannel"
   185  			sysProfile = genesisconfig.Load(network.SystemChannel.Profile, network.RootDir)
   186  			Expect(sysProfile.Orderer).NotTo(BeNil())
   187  			appProfile := genesisconfig.Load(network.ProfileForChannel(channel), network.RootDir)
   188  			Expect(appProfile).NotTo(BeNil())
   189  			o := *sysProfile.Orderer
   190  			appProfile.Orderer = &o
   191  			appProfile.Orderer.EtcdRaft = proto.Clone(sysProfile.Orderer.EtcdRaft).(*etcdraft.ConfigMetadata)
   192  			appProfile.Orderer.EtcdRaft.Options.HeartbeatTick = appProfile.Orderer.EtcdRaft.Options.ElectionTick
   193  			configtx, err := encoder.MakeChannelCreationTransactionWithSystemChannelContext(channel, nil, appProfile, sysProfile)
   194  			Expect(err).NotTo(HaveOccurred())
   195  			data, err = proto.Marshal(configtx)
   196  			Expect(err).NotTo(HaveOccurred())
   197  			ioutil.WriteFile(network.CreateChannelTxPath(channel), data, 0644)
   198  
   199  			By("Submitting malformed channel creation config tx to orderer")
   200  			peer1org1 := network.Peer("Org1", "peer1")
   201  			peer1org2 := network.Peer("Org2", "peer1")
   202  
   203  			exitCode := network.CreateChannelExitCode(channel, orderer, peer1org1, peer1org1, peer1org2, orderer)
   204  			Expect(exitCode).NotTo(Equal(0))
   205  			Consistently(process.Wait).ShouldNot(Receive()) // malformed tx should not crash orderer
   206  			Expect(runner.Err()).To(gbytes.Say(`invalid new config metdadata: ElectionTick \(10\) must be greater than HeartbeatTick \(10\)`))
   207  
   208  			By("Submitting channel config update with illegal value")
   209  			channel = network.SystemChannel.Name
   210  			config := nwo.GetConfig(network, peer1org1, orderer, channel)
   211  			updatedConfig := proto.Clone(config).(*common.Config)
   212  
   213  			consensusTypeConfigValue := updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"]
   214  			consensusTypeValue := &protosorderer.ConsensusType{}
   215  			Expect(proto.Unmarshal(consensusTypeConfigValue.Value, consensusTypeValue)).To(Succeed())
   216  
   217  			metadata := &etcdraft.ConfigMetadata{}
   218  			Expect(proto.Unmarshal(consensusTypeValue.Metadata, metadata)).To(Succeed())
   219  
   220  			metadata.Options.HeartbeatTick = 10
   221  			metadata.Options.ElectionTick = 10
   222  
   223  			newMetadata, err := proto.Marshal(metadata)
   224  			Expect(err).NotTo(HaveOccurred())
   225  			consensusTypeValue.Metadata = newMetadata
   226  
   227  			updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"] = &common.ConfigValue{
   228  				ModPolicy: "Admins",
   229  				Value:     protoutil.MarshalOrPanic(consensusTypeValue),
   230  			}
   231  
   232  			sess := nwo.UpdateOrdererConfigSession(network, orderer, channel, config, updatedConfig, peer1org1, orderer)
   233  			Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   234  			Expect(sess.Err).To(gbytes.Say(`invalid new config metdadata: ElectionTick \(10\) must be greater than HeartbeatTick \(10\)`))
   235  		})
   236  	})
   237  
   238  	When("a single node cluster is expanded", func() {
   239  		It("is still possible to onboard the new cluster member", func() {
   240  			launch := func(o *nwo.Orderer) {
   241  				runner := network.OrdererRunner(o)
   242  				ordererRunners = append(ordererRunners, runner)
   243  
   244  				process := ifrit.Invoke(runner)
   245  				Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
   246  				ordererProcesses = append(ordererProcesses, process)
   247  			}
   248  
   249  			layout := nwo.BasicEtcdRaft()
   250  
   251  			network = nwo.New(layout, testDir, client, StartPort(), components)
   252  			orderer := network.Orderer("orderer")
   253  
   254  			peer = network.Peer("Org1", "peer1")
   255  
   256  			network.GenerateConfigTree()
   257  			network.Bootstrap()
   258  
   259  			By("Launching the orderer")
   260  			launch(orderer)
   261  
   262  			By("Checking that it elected itself as a leader")
   263  			findLeader(ordererRunners)
   264  
   265  			By("Extending the network configuration to add a new orderer")
   266  			orderer2 := &nwo.Orderer{
   267  				Name:         "orderer2",
   268  				Organization: "OrdererOrg",
   269  			}
   270  			ports := nwo.Ports{}
   271  			for _, portName := range nwo.OrdererPortNames() {
   272  				ports[portName] = network.ReservePort()
   273  			}
   274  			network.PortsByOrdererID[orderer2.ID()] = ports
   275  			network.Orderers = append(network.Orderers, orderer2)
   276  			network.GenerateOrdererConfig(orderer2)
   277  			extendNetwork(network)
   278  
   279  			secondOrdererCertificatePath := filepath.Join(network.OrdererLocalTLSDir(orderer2), "server.crt")
   280  			secondOrdererCertificate, err := ioutil.ReadFile(secondOrdererCertificatePath)
   281  			Expect(err).NotTo(HaveOccurred())
   282  
   283  			By("Adding the second orderer")
   284  			addConsenter(network, peer, orderer, "systemchannel", etcdraft.Consenter{
   285  				ServerTlsCert: secondOrdererCertificate,
   286  				ClientTlsCert: secondOrdererCertificate,
   287  				Host:          "127.0.0.1",
   288  				Port:          uint32(network.OrdererPort(orderer2, nwo.ClusterPort)),
   289  			})
   290  
   291  			By("Obtaining the last config block from the orderer")
   292  			// Get the last config block of the system channel
   293  			configBlock := nwo.GetConfigBlock(network, peer, orderer, "systemchannel")
   294  			// Plant it in the file system of orderer2, the new node to be onboarded.
   295  			err = ioutil.WriteFile(filepath.Join(testDir, "systemchannel_block.pb"), protoutil.MarshalOrPanic(configBlock), 0644)
   296  			Expect(err).NotTo(HaveOccurred())
   297  
   298  			By("Waiting for the existing orderer to relinquish its leadership")
   299  			Eventually(ordererRunners[0].Err(), network.EventuallyTimeout).Should(gbytes.Say("1 stepped down to follower since quorum is not active"))
   300  			Eventually(ordererRunners[0].Err(), network.EventuallyTimeout).Should(gbytes.Say("No leader is present, cluster size is 2"))
   301  			By("Launching the second orderer")
   302  			launch(orderer2)
   303  			By("Waiting for a leader to be re-elected")
   304  			findLeader(ordererRunners)
   305  		})
   306  	})
   307  
   308  	When("the orderer certificates are all rotated", func() {
   309  		It("is possible to rotate certificate by adding & removing cert in single config", func() {
   310  			layout := nwo.MultiNodeEtcdRaft()
   311  			network = nwo.New(layout, testDir, client, StartPort(), components)
   312  			o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
   313  			orderers := []*nwo.Orderer{o1, o2, o3}
   314  
   315  			peer = network.Peer("Org1", "peer1")
   316  
   317  			network.GenerateConfigTree()
   318  			network.Bootstrap()
   319  
   320  			By("Launching the orderers")
   321  			for _, o := range orderers {
   322  				runner := network.OrdererRunner(o)
   323  				ordererRunners = append(ordererRunners, runner)
   324  				process := ifrit.Invoke(runner)
   325  				ordererProcesses = append(ordererProcesses, process)
   326  			}
   327  
   328  			for _, ordererProc := range ordererProcesses {
   329  				Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
   330  			}
   331  
   332  			By("Finding leader")
   333  			leader := findLeader(ordererRunners)
   334  			leaderIndex := leader - 1
   335  			blockSeq := 0
   336  
   337  			By("Checking that all orderers are online")
   338  			assertBlockReception(map[string]int{
   339  				"systemchannel": blockSeq,
   340  			}, orderers, peer, network)
   341  
   342  			By("Preparing new certificates for the orderer nodes")
   343  			extendNetwork(network)
   344  			certificateRotations := refreshOrdererPEMs(network)
   345  
   346  			swap := func(o *nwo.Orderer, certificate []byte, c etcdraft.Consenter) {
   347  				updateEtcdRaftMetadata(network, peer, o, network.SystemChannel.Name, func(metadata *etcdraft.ConfigMetadata) {
   348  					var newConsenters []*etcdraft.Consenter
   349  					for _, consenter := range metadata.Consenters {
   350  						if bytes.Equal(consenter.ClientTlsCert, certificate) || bytes.Equal(consenter.ServerTlsCert, certificate) {
   351  							continue
   352  						}
   353  						newConsenters = append(newConsenters, consenter)
   354  					}
   355  					newConsenters = append(newConsenters, &c)
   356  
   357  					metadata.Consenters = newConsenters
   358  				})
   359  				blockSeq++
   360  			}
   361  
   362  			rotate := func(target int) {
   363  				// submit a config tx to rotate the cert of an orderer.
   364  				// The orderer being rotated is going to be unavailable
   365  				// eventually, therefore submitter of tx is different
   366  				// from the target, so the configuration can be reliably
   367  				// checked.
   368  				submitter := (target + 1) % 3
   369  				rotation := certificateRotations[target]
   370  				targetOrderer := network.Orderers[target]
   371  				remainder := func() []*nwo.Orderer {
   372  					var ret []*nwo.Orderer
   373  					for i, o := range network.Orderers {
   374  						if i == target {
   375  							continue
   376  						}
   377  						ret = append(ret, o)
   378  					}
   379  					return ret
   380  				}()
   381  				submitterOrderer := network.Orderers[submitter]
   382  				port := network.OrdererPort(targetOrderer, nwo.ClusterPort)
   383  
   384  				fmt.Fprintf(GinkgoWriter, "Rotating certificate of orderer node %d\n", target+1)
   385  				swap(submitterOrderer, rotation.oldCert, etcdraft.Consenter{
   386  					ServerTlsCert: rotation.newCert,
   387  					ClientTlsCert: rotation.newCert,
   388  					Host:          "127.0.0.1",
   389  					Port:          uint32(port),
   390  				})
   391  
   392  				By("Waiting for all orderers to sync")
   393  				assertBlockReception(map[string]int{
   394  					"systemchannel": blockSeq,
   395  				}, remainder, peer, network)
   396  
   397  				By("Waiting for rotated node to be unavailable")
   398  				c := commands.ChannelFetch{
   399  					ChannelID:  network.SystemChannel.Name,
   400  					Block:      "newest",
   401  					OutputFile: "/dev/null",
   402  					Orderer:    network.OrdererAddress(targetOrderer, nwo.ClusterPort),
   403  				}
   404  				Eventually(func() string {
   405  					sess, err := network.OrdererAdminSession(targetOrderer, peer, c)
   406  					Expect(err).NotTo(HaveOccurred())
   407  					Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
   408  					if sess.ExitCode() != 0 {
   409  						return fmt.Sprintf("exit code is %d: %s", sess.ExitCode(), string(sess.Err.Contents()))
   410  					}
   411  					sessErr := string(sess.Err.Contents())
   412  					expected := fmt.Sprintf("Received block: %d", blockSeq)
   413  					if strings.Contains(sessErr, expected) {
   414  						return ""
   415  					}
   416  					return sessErr
   417  				}, network.EventuallyTimeout, time.Second).ShouldNot(BeEmpty())
   418  
   419  				By("Killing the orderer")
   420  				ordererProcesses[target].Signal(syscall.SIGTERM)
   421  				Eventually(ordererProcesses[target].Wait(), network.EventuallyTimeout).Should(Receive())
   422  
   423  				By("Starting the orderer again")
   424  				ordererRunner := network.OrdererRunner(targetOrderer)
   425  				ordererRunners = append(ordererRunners, ordererRunner)
   426  				ordererProcesses[target] = ifrit.Invoke(ordererRunner)
   427  				Eventually(ordererProcesses[target].Ready(), network.EventuallyTimeout).Should(BeClosed())
   428  
   429  				By("And waiting for it to stabilize")
   430  				assertBlockReception(map[string]int{
   431  					"systemchannel": blockSeq,
   432  				}, orderers, peer, network)
   433  			}
   434  
   435  			By(fmt.Sprintf("Rotating cert on leader %d", leader))
   436  			rotate(leaderIndex)
   437  
   438  			By("Rotating certificates of other orderer nodes")
   439  			for i := range certificateRotations {
   440  				if i != leaderIndex {
   441  					rotate(i)
   442  				}
   443  			}
   444  		})
   445  
   446  		It("is still possible to onboard new orderers", func() {
   447  			// In this test, we have 3 OSNs and we rotate their TLS certificates one by one,
   448  			// by adding the future certificate to the channel, killing the OSN to make it
   449  			// grab the new certificate, and then removing the old certificate from the channel.
   450  
   451  			// After we completely rotate all the certificates, we put the last config block
   452  			// of the system channel into the file system of orderer4, and then launch it,
   453  			// and ensure it onboards and pulls channels testchannel only, and not testchannel2
   454  			// which it is not part of.
   455  
   456  			// Consenter i after its certificate is rotated is denoted as consenter i'
   457  			// The blocks of channels contain the following updates:
   458  			//    | system channel height | testchannel  height  | update description
   459  			// ------------------------------------------------------------------------
   460  			// 0  |            2          |         1            | adding consenter 1'
   461  			// 1  |            3          |         2            | removing consenter 1
   462  			// 2  |            4          |         3            | adding consenter 2'
   463  			// 3  |            5          |         4            | removing consenter 2
   464  			// 4  |            6          |         5            | adding consenter 3'
   465  			// 5  |            7          |         6            | removing consenter 3
   466  			// 6  |            8          |         6            | creating channel testchannel2
   467  			// 7  |            9          |         6            | creating channel testchannel3
   468  			// 8  |            10         |         7            | adding consenter 4
   469  
   470  			layout := nwo.MultiNodeEtcdRaft()
   471  			layout.Channels = append(layout.Channels, &nwo.Channel{
   472  				Name:    "testchannel2",
   473  				Profile: "TwoOrgsChannel",
   474  			}, &nwo.Channel{
   475  				Name:    "testchannel3",
   476  				Profile: "TwoOrgsChannel",
   477  			})
   478  
   479  			network = nwo.New(layout, testDir, client, StartPort(), components)
   480  			o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
   481  			orderers := []*nwo.Orderer{o1, o2, o3}
   482  
   483  			peer = network.Peer("Org1", "peer1")
   484  
   485  			network.GenerateConfigTree()
   486  			network.Bootstrap()
   487  
   488  			By("Launching the orderers")
   489  			for _, o := range orderers {
   490  				runner := network.OrdererRunner(o)
   491  				ordererRunners = append(ordererRunners, runner)
   492  				process := ifrit.Invoke(runner)
   493  				ordererProcesses = append(ordererProcesses, process)
   494  			}
   495  
   496  			for _, ordererProc := range ordererProcesses {
   497  				Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
   498  			}
   499  
   500  			By("Checking that all orderers are online")
   501  			assertBlockReception(map[string]int{
   502  				"systemchannel": 0,
   503  			}, orderers, peer, network)
   504  
   505  			By("Creating a channel and checking that all orderers got the channel creation")
   506  			network.CreateChannel("testchannel", network.Orderers[0], peer)
   507  			assertBlockReception(map[string]int{
   508  				"systemchannel": 1,
   509  				"testchannel":   0,
   510  			}, orderers, peer, network)
   511  
   512  			By("Preparing new certificates for the orderer nodes")
   513  			extendNetwork(network)
   514  			certificateRotations := refreshOrdererPEMs(network)
   515  
   516  			expectedBlockHeightsPerChannel := []map[string]int{
   517  				{"systemchannel": 2, "testchannel": 1},
   518  				{"systemchannel": 3, "testchannel": 2},
   519  				{"systemchannel": 4, "testchannel": 3},
   520  				{"systemchannel": 5, "testchannel": 4},
   521  				{"systemchannel": 6, "testchannel": 5},
   522  				{"systemchannel": 7, "testchannel": 6},
   523  			}
   524  
   525  			for i, rotation := range certificateRotations {
   526  				o := network.Orderers[i]
   527  				port := network.OrdererPort(o, nwo.ClusterPort)
   528  
   529  				By(fmt.Sprintf("Adding the future certificate of orderer node %d", i))
   530  				for _, channelName := range []string{"systemchannel", "testchannel"} {
   531  					addConsenter(network, peer, o, channelName, etcdraft.Consenter{
   532  						ServerTlsCert: rotation.newCert,
   533  						ClientTlsCert: rotation.newCert,
   534  						Host:          "127.0.0.1",
   535  						Port:          uint32(port),
   536  					})
   537  				}
   538  
   539  				By("Waiting for all orderers to sync")
   540  				assertBlockReception(expectedBlockHeightsPerChannel[i*2], orderers, peer, network)
   541  
   542  				By("Killing the orderer")
   543  				ordererProcesses[i].Signal(syscall.SIGTERM)
   544  				Eventually(ordererProcesses[i].Wait(), network.EventuallyTimeout).Should(Receive())
   545  
   546  				By("Starting the orderer again")
   547  				ordererRunner := network.OrdererRunner(orderers[i])
   548  				ordererRunners = append(ordererRunners, ordererRunner)
   549  				ordererProcesses[i] = ifrit.Invoke(ordererRunner)
   550  				Eventually(ordererProcesses[i].Ready(), network.EventuallyTimeout).Should(BeClosed())
   551  
   552  				By("And waiting for it to stabilize")
   553  				assertBlockReception(expectedBlockHeightsPerChannel[i*2], orderers, peer, network)
   554  
   555  				By("Removing the previous certificate of the old orderer")
   556  				for _, channelName := range []string{"systemchannel", "testchannel"} {
   557  					removeConsenter(network, peer, network.Orderers[(i+1)%len(network.Orderers)], channelName, rotation.oldCert)
   558  				}
   559  
   560  				By("Waiting for all orderers to sync")
   561  				assertBlockReception(expectedBlockHeightsPerChannel[i*2+1], orderers, peer, network)
   562  			}
   563  
   564  			By("Creating testchannel2")
   565  			network.CreateChannel("testchannel2", network.Orderers[0], peer)
   566  			assertBlockReception(map[string]int{
   567  				"systemchannel": 8,
   568  			}, orderers, peer, network)
   569  
   570  			By("Creating testchannel3")
   571  			network.CreateChannel("testchannel3", network.Orderers[0], peer)
   572  			assertBlockReception(map[string]int{
   573  				"systemchannel": 9,
   574  			}, orderers, peer, network)
   575  
   576  			o4 := &nwo.Orderer{
   577  				Name:         "orderer4",
   578  				Organization: "OrdererOrg",
   579  			}
   580  
   581  			By("Configuring orderer4 in the network")
   582  			ports := nwo.Ports{}
   583  			for _, portName := range nwo.OrdererPortNames() {
   584  				ports[portName] = network.ReservePort()
   585  			}
   586  			network.PortsByOrdererID[o4.ID()] = ports
   587  
   588  			network.Orderers = append(network.Orderers, o4)
   589  			network.GenerateOrdererConfig(network.Orderer("orderer4"))
   590  
   591  			By("Adding orderer4 to the channels")
   592  			orderer4CertificatePath := filepath.Join(network.OrdererLocalTLSDir(o4), "server.crt")
   593  			orderer4Certificate, err := ioutil.ReadFile(orderer4CertificatePath)
   594  			Expect(err).NotTo(HaveOccurred())
   595  			for _, channel := range []string{"systemchannel", "testchannel"} {
   596  				addConsenter(network, peer, o1, channel, etcdraft.Consenter{
   597  					ServerTlsCert: orderer4Certificate,
   598  					ClientTlsCert: orderer4Certificate,
   599  					Host:          "127.0.0.1",
   600  					Port:          uint32(network.OrdererPort(o4, nwo.ClusterPort)),
   601  				})
   602  			}
   603  
   604  			By("Ensuring all orderers know about orderer4's addition")
   605  			assertBlockReception(map[string]int{
   606  				"systemchannel": 10,
   607  				"testchannel":   7,
   608  			}, orderers, peer, network)
   609  
   610  			By("Broadcasting envelope to testchannel")
   611  			env := CreateBroadcastEnvelope(network, peer, "testchannel", []byte("hello"))
   612  			resp, err := nwo.Broadcast(network, o1, env)
   613  			Expect(err).NotTo(HaveOccurred())
   614  			Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   615  
   616  			assertBlockReception(map[string]int{
   617  				"testchannel": 8,
   618  			}, orderers, peer, network)
   619  
   620  			By("Corrupting the readers policy of testchannel3")
   621  			revokeReaderAccess(network, "testchannel3", o3, peer)
   622  
   623  			// Get the last config block of the system channel
   624  			configBlock := nwo.GetConfigBlock(network, peer, o1, "systemchannel")
   625  			// Plant it in the file system of orderer4, the new node to be onboarded.
   626  			err = ioutil.WriteFile(filepath.Join(testDir, "systemchannel_block.pb"), protoutil.MarshalOrPanic(configBlock), 0644)
   627  			Expect(err).NotTo(HaveOccurred())
   628  
   629  			By("Launching orderer4")
   630  			orderers = append(orderers, o4)
   631  			orderer4Runner := network.OrdererRunner(o4)
   632  			ordererRunners = append(ordererRunners, orderer4Runner)
   633  			// Spawn orderer4's process
   634  			o4process := ifrit.Invoke(orderer4Runner)
   635  			Eventually(o4process.Ready(), network.EventuallyTimeout).Should(BeClosed())
   636  			ordererProcesses = append(ordererProcesses, o4process)
   637  
   638  			By("And waiting for it to sync with the rest of the orderers")
   639  			assertBlockReception(map[string]int{
   640  				"systemchannel": 10,
   641  				"testchannel":   8,
   642  			}, orderers, peer, network)
   643  
   644  			By("Ensuring orderer4 doesn't serve testchannel2 and testchannel3")
   645  			env = CreateBroadcastEnvelope(network, peer, "testchannel2", []byte("hello"))
   646  			resp, err = nwo.Broadcast(network, o4, env)
   647  			Expect(err).NotTo(HaveOccurred())
   648  			Expect(resp.Status).To(Equal(common.Status_SERVICE_UNAVAILABLE))
   649  
   650  			env = CreateBroadcastEnvelope(network, peer, "testchannel3", []byte("hello"))
   651  			resp, err = nwo.Broadcast(network, o4, env)
   652  			Expect(err).NotTo(HaveOccurred())
   653  			Expect(resp.Status).To(Equal(common.Status_SERVICE_UNAVAILABLE))
   654  
   655  			belongRegex := `\QI do not belong to channel testchannel2 or am forbidden pulling it (not in the channel), skipping chain retrieval\E`
   656  			forbiddenRegex := `\QI do not belong to channel testchannel3 or am forbidden pulling it (forbidden pulling the channel), skipping chain retrieval\E`
   657  
   658  			Expect(orderer4Runner.Err()).To(gbytes.Say(belongRegex + "|" + forbiddenRegex))
   659  			Expect(orderer4Runner.Err()).To(gbytes.Say(belongRegex + "|" + forbiddenRegex))
   660  
   661  			By("Adding orderer4 to testchannel2")
   662  			addConsenter(network, peer, o1, "testchannel2", etcdraft.Consenter{
   663  				ServerTlsCert: orderer4Certificate,
   664  				ClientTlsCert: orderer4Certificate,
   665  				Host:          "127.0.0.1",
   666  				Port:          uint32(network.OrdererPort(o4, nwo.ClusterPort)),
   667  			})
   668  
   669  			By("Waiting for orderer4 and to replicate testchannel2")
   670  			assertBlockReception(map[string]int{
   671  				"testchannel2": 1,
   672  			}, []*nwo.Orderer{o4}, peer, network)
   673  
   674  			By("Ensuring orderer4 doesn't have any errors in the logs")
   675  			Consistently(orderer4Runner.Err()).ShouldNot(gbytes.Say("ERRO"))
   676  
   677  			By("Submitting a transaction through orderer4")
   678  			env = CreateBroadcastEnvelope(network, peer, "testchannel2", []byte("hello"))
   679  			resp, err = nwo.Broadcast(network, o4, env)
   680  			Expect(err).NotTo(HaveOccurred())
   681  			Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   682  
   683  			By("And ensuring it is propagated amongst all orderers")
   684  			assertBlockReception(map[string]int{
   685  				"testchannel2": 2,
   686  			}, orderers, peer, network)
   687  		})
   688  	})
   689  
   690  	When("an orderer channel is created with a subset of nodes", func() {
   691  		It("is still possible to onboard a new orderer to the channel", func() {
   692  			network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components)
   693  			network.Profiles = append(network.Profiles, &nwo.Profile{
   694  				Name:          "myprofile",
   695  				Consortium:    "SampleConsortium",
   696  				Orderers:      []string{"orderer1"},
   697  				Organizations: []string{"Org1"},
   698  			})
   699  			network.Channels = append(network.Channels, &nwo.Channel{
   700  				Name:        "mychannel",
   701  				Profile:     "myprofile",
   702  				BaseProfile: "SampleDevModeEtcdRaft",
   703  			})
   704  
   705  			peer = network.Peer("Org1", "peer1")
   706  
   707  			network.GenerateConfigTree()
   708  			network.Bootstrap()
   709  
   710  			o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
   711  			orderers := []*nwo.Orderer{o1, o2, o3}
   712  			By("Launching the orderers")
   713  			for _, o := range orderers {
   714  				runner := network.OrdererRunner(o)
   715  				ordererRunners = append(ordererRunners, runner)
   716  				process := ifrit.Invoke(runner)
   717  				ordererProcesses = append(ordererProcesses, process)
   718  			}
   719  
   720  			for _, ordererProc := range ordererProcesses {
   721  				Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
   722  			}
   723  
   724  			By("Waiting for the system channel to be available")
   725  			assertBlockReception(map[string]int{
   726  				"systemchannel": 0,
   727  			}, orderers, peer, network)
   728  
   729  			By("Creating a channel with a subset of orderers")
   730  			network.CreateChannel("mychannel", o1, peer, peer, o1)
   731  
   732  			By("Waiting for the channel to be available")
   733  			assertBlockReception(map[string]int{
   734  				"mychannel": 0,
   735  			}, []*nwo.Orderer{o1}, peer, network)
   736  
   737  			By("Ensuring only orderer1 services the channel")
   738  			ensureEvicted(o2, peer, network, "mychannel")
   739  			ensureEvicted(o3, peer, network, "mychannel")
   740  
   741  			By("Adding orderer2 to the channel")
   742  			ordererCertificatePath := filepath.Join(network.OrdererLocalTLSDir(o2), "server.crt")
   743  			ordererCertificate, err := ioutil.ReadFile(ordererCertificatePath)
   744  			Expect(err).NotTo(HaveOccurred())
   745  
   746  			addConsenter(network, peer, o1, "mychannel", etcdraft.Consenter{
   747  				ServerTlsCert: ordererCertificate,
   748  				ClientTlsCert: ordererCertificate,
   749  				Host:          "127.0.0.1",
   750  				Port:          uint32(network.OrdererPort(o2, nwo.ClusterPort)),
   751  			})
   752  
   753  			By("Waiting for orderer2 to join the channel")
   754  			assertBlockReception(map[string]int{
   755  				"mychannel": 1,
   756  			}, []*nwo.Orderer{o1, o2}, peer, network)
   757  
   758  			By("Adding orderer3 to the channel")
   759  			ordererCertificatePath = filepath.Join(network.OrdererLocalTLSDir(o3), "server.crt")
   760  			ordererCertificate, err = ioutil.ReadFile(ordererCertificatePath)
   761  			Expect(err).NotTo(HaveOccurred())
   762  			addConsenter(network, peer, o1, "mychannel", etcdraft.Consenter{
   763  				ServerTlsCert: ordererCertificate,
   764  				ClientTlsCert: ordererCertificate,
   765  				Host:          "127.0.0.1",
   766  				Port:          uint32(network.OrdererPort(o3, nwo.ClusterPort)),
   767  			})
   768  
   769  			By("Waiting for orderer3 to join the channel")
   770  			assertBlockReception(map[string]int{
   771  				"mychannel": 2,
   772  			}, orderers, peer, network)
   773  		})
   774  	})
   775  
   776  	When("orderer cluster is not healthy", func() {
   777  		var (
   778  			o1, o2 *nwo.Orderer
   779  		)
   780  
   781  		BeforeEach(func() {
   782  			network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components)
   783  			network.GenerateConfigTree()
   784  			network.Bootstrap()
   785  
   786  			o1, o2 = network.Orderer("orderer1"), network.Orderer("orderer2")
   787  			orderers := []*nwo.Orderer{o1, o2}
   788  			By("Launching the orderers")
   789  			for _, o := range orderers {
   790  				runner := network.OrdererRunner(o)
   791  				ordererRunners = append(ordererRunners, runner)
   792  				process := ifrit.Invoke(runner)
   793  				ordererProcesses = append(ordererProcesses, process)
   794  			}
   795  
   796  			for _, ordererProc := range ordererProcesses {
   797  				Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
   798  			}
   799  		})
   800  
   801  		AfterEach(func() {
   802  			for _, ordererInstance := range ordererProcesses {
   803  				ordererInstance.Signal(syscall.SIGTERM)
   804  				Eventually(ordererInstance.Wait(), network.EventuallyTimeout).Should(Receive())
   805  			}
   806  		})
   807  
   808  		It("refuses to reconfig if it results in quorum loss", func() {
   809  			By("Waiting for them to elect a leader")
   810  			findLeader(ordererRunners)
   811  
   812  			extendNetwork(network)
   813  			certificatesOfOrderers := refreshOrdererPEMs(network)
   814  
   815  			By("Removing alive node from 2/3 cluster")
   816  			peer := network.Peer("Org1", "peer1")
   817  			current, updated := consenterRemover(network, peer, o2, network.SystemChannel.Name, certificatesOfOrderers[1].oldCert)
   818  			Eventually(func() []byte {
   819  				sess := nwo.UpdateOrdererConfigSession(network, o2, network.SystemChannel.Name, current, updated, peer, o2)
   820  				Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   821  				return sess.Err.Contents()
   822  			}, network.EventuallyTimeout).Should(ContainSubstring("2 out of 3 nodes are alive, configuration will result in quorum loss"))
   823  
   824  			By("Adding node to 2/3 cluster")
   825  			current, updated = consenterAdder(
   826  				network,
   827  				peer,
   828  				o2,
   829  				network.SystemChannel.Name,
   830  				etcdraft.Consenter{
   831  					ServerTlsCert: certificatesOfOrderers[0].newCert,
   832  					ClientTlsCert: certificatesOfOrderers[0].newCert,
   833  					Host:          "127.0.0.1",
   834  					Port:          uint32(network.OrdererPort(o1, nwo.ListenPort)),
   835  				},
   836  			)
   837  			sess := nwo.UpdateOrdererConfigSession(network, o2, network.SystemChannel.Name, current, updated, peer, o2)
   838  			Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
   839  			Expect(string(sess.Err.Contents())).To(ContainSubstring("2 out of 3 nodes are alive, configuration will result in quorum loss"))
   840  		})
   841  	})
   842  
   843  	When("an orderer node is evicted", func() {
   844  		BeforeEach(func() {
   845  			ordererRunners = nil
   846  			ordererProcesses = nil
   847  
   848  			network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components)
   849  
   850  			peer = network.Peer("Org1", "peer1")
   851  
   852  			network.GenerateConfigTree()
   853  			network.Bootstrap()
   854  
   855  			o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
   856  			orderers := []*nwo.Orderer{o1, o2, o3}
   857  			By("Launching the orderers")
   858  			for _, o := range orderers {
   859  				runner := network.OrdererRunner(o)
   860  				ordererRunners = append(ordererRunners, runner)
   861  				process := ifrit.Invoke(runner)
   862  				ordererProcesses = append(ordererProcesses, process)
   863  			}
   864  
   865  			for _, ordererProc := range ordererProcesses {
   866  				Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
   867  			}
   868  		})
   869  
   870  		AfterEach(func() {
   871  			for _, ordererInstance := range ordererProcesses {
   872  				ordererInstance.Signal(syscall.SIGTERM)
   873  				Eventually(ordererInstance.Wait(), network.EventuallyTimeout).Should(Receive())
   874  			}
   875  		})
   876  
   877  		It("doesn't complain and does it obediently", func() {
   878  			o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
   879  			orderers := []*nwo.Orderer{o1, o2, o3}
   880  
   881  			By("Waiting for them to elect a leader")
   882  			firstEvictedNode := findLeader(ordererRunners) - 1
   883  
   884  			By("Removing the leader from 3-node channel")
   885  			server1CertBytes, err := ioutil.ReadFile(filepath.Join(network.OrdererLocalTLSDir(orderers[firstEvictedNode]), "server.crt"))
   886  			Expect(err).To(Not(HaveOccurred()))
   887  
   888  			removeConsenter(network, peer, network.Orderers[(firstEvictedNode+1)%3], "systemchannel", server1CertBytes)
   889  
   890  			var survivedOrdererRunners []*ginkgomon.Runner
   891  			for i := range orderers {
   892  				if i == firstEvictedNode {
   893  					continue
   894  				}
   895  
   896  				survivedOrdererRunners = append(survivedOrdererRunners, ordererRunners[i])
   897  			}
   898  
   899  			secondEvictedNode := findLeader(survivedOrdererRunners) - 1
   900  
   901  			var surviver int
   902  			for i := range orderers {
   903  				if i != firstEvictedNode && i != secondEvictedNode {
   904  					surviver = i
   905  					break
   906  				}
   907  			}
   908  
   909  			const stopMsg = "Raft node stopped channel=systemchannel"
   910  			fmt.Fprintln(GinkgoWriter, "Ensuring the evicted orderer stops rafting on channel systemchannel")
   911  			Eventually(ordererRunners[firstEvictedNode].Err(), network.EventuallyTimeout, time.Second).Should(gbytes.Say(stopMsg))
   912  
   913  			By("Ensuring the evicted orderer now doesn't serve clients")
   914  			ensureEvicted(orderers[firstEvictedNode], peer, network, "systemchannel")
   915  
   916  			By("Removing the leader from 2-node channel")
   917  			server2CertBytes, err := ioutil.ReadFile(filepath.Join(network.OrdererLocalTLSDir(orderers[secondEvictedNode]), "server.crt"))
   918  			Expect(err).To(Not(HaveOccurred()))
   919  
   920  			removeConsenter(network, peer, orderers[surviver], "systemchannel", server2CertBytes)
   921  			findLeader([]*ginkgomon.Runner{ordererRunners[surviver]})
   922  
   923  			fmt.Fprintln(GinkgoWriter, "Ensuring the other orderer detect the eviction of the node on channel systemchannel")
   924  			Eventually(ordererRunners[secondEvictedNode].Err(), network.EventuallyTimeout, time.Second).Should(gbytes.Say(stopMsg))
   925  
   926  			By("Ensuring the evicted orderer now doesn't serve clients")
   927  			ensureEvicted(orderers[secondEvictedNode], peer, network, "systemchannel")
   928  
   929  			By("Re-adding first evicted orderer")
   930  			addConsenter(network, peer, network.Orderers[surviver], "systemchannel", etcdraft.Consenter{
   931  				Host:          "127.0.0.1",
   932  				Port:          uint32(network.OrdererPort(orderers[firstEvictedNode], nwo.ClusterPort)),
   933  				ClientTlsCert: server1CertBytes,
   934  				ServerTlsCert: server1CertBytes,
   935  			})
   936  
   937  			By("Ensuring re-added orderer starts serving system channel")
   938  			assertBlockReception(map[string]int{
   939  				"systemchannel": 3,
   940  			}, []*nwo.Orderer{orderers[firstEvictedNode]}, peer, network)
   941  
   942  			env := CreateBroadcastEnvelope(network, orderers[secondEvictedNode], network.SystemChannel.Name, []byte("foo"))
   943  			resp, err := nwo.Broadcast(network, orderers[surviver], env)
   944  			Expect(err).NotTo(HaveOccurred())
   945  			Expect(resp.Status).To(Equal(common.Status_SUCCESS))
   946  		})
   947  
   948  		It("notices it even if it is down at the time of its eviction", func() {
   949  			o1 := network.Orderer("orderer1")
   950  			o2 := network.Orderer("orderer2")
   951  			o3 := network.Orderer("orderer3")
   952  
   953  			orderers := []*nwo.Orderer{o1, o2, o3}
   954  
   955  			By("Waiting for them to elect a leader")
   956  			findLeader(ordererRunners)
   957  
   958  			By("Creating a channel")
   959  			network.CreateChannel("testchannel", o1, peer)
   960  
   961  			assertBlockReception(map[string]int{
   962  				"testchannel":   0,
   963  				"systemchannel": 1,
   964  			}, []*nwo.Orderer{o1, o2, o3}, peer, network)
   965  
   966  			By("Killing the orderer")
   967  			ordererProcesses[0].Signal(syscall.SIGTERM)
   968  			Eventually(ordererProcesses[0].Wait(), network.EventuallyTimeout).Should(Receive())
   969  
   970  			// We need to wait for stabilization, as we might have killed the leader OSN.
   971  			By("Waiting for the channel to stabilize after killing the orderer")
   972  			assertBlockReception(map[string]int{
   973  				"testchannel":   0,
   974  				"systemchannel": 1,
   975  			}, []*nwo.Orderer{o2, o3}, peer, network)
   976  
   977  			By("Removing the first orderer from an application channel")
   978  			extendNetwork(network)
   979  			certificatesOfOrderers := refreshOrdererPEMs(network)
   980  			removeConsenter(network, peer, o2, "testchannel", certificatesOfOrderers[0].oldCert)
   981  
   982  			certPath := certificatesOfOrderers[0].dstFile
   983  			keyFile := strings.Replace(certPath, "server.crt", "server.key", -1)
   984  			err := ioutil.WriteFile(certPath, certificatesOfOrderers[0].oldCert, 0644)
   985  			Expect(err).To(Not(HaveOccurred()))
   986  			err = ioutil.WriteFile(keyFile, certificatesOfOrderers[0].oldKey, 0644)
   987  			Expect(err).To(Not(HaveOccurred()))
   988  
   989  			By("Starting the orderer again")
   990  			ordererRunner := network.OrdererRunner(orderers[0])
   991  			ordererRunners[0] = ordererRunner
   992  			ordererProcesses[0] = ifrit.Invoke(ordererRunner)
   993  			Eventually(ordererProcesses[0].Ready(), network.EventuallyTimeout).Should(BeClosed())
   994  
   995  			By("Ensuring the remaining OSNs reject authentication")
   996  			Eventually(ordererRunners[1].Err(), time.Minute, time.Second).Should(gbytes.Say("certificate extracted from TLS connection isn't authorized"))
   997  			Eventually(ordererRunners[2].Err(), time.Minute, time.Second).Should(gbytes.Say("certificate extracted from TLS connection isn't authorized"))
   998  
   999  			By("Ensuring it detects its eviction")
  1000  			evictionDetection := gbytes.Say(`Detected our own eviction from the channel in block \[1\] channel=testchannel`)
  1001  			Eventually(ordererRunner.Err(), time.Minute, time.Second).Should(evictionDetection)
  1002  
  1003  			By("Ensuring all blocks are pulled up to the block that evicts the OSN")
  1004  			Eventually(ordererRunner.Err(), time.Minute, time.Second).Should(gbytes.Say("Periodic check is stopping. channel=testchannel"))
  1005  			Eventually(ordererRunner.Err(), time.Minute, time.Second).Should(gbytes.Say("Pulled all blocks up to eviction block. channel=testchannel"))
  1006  
  1007  			By("Killing the evicted orderer")
  1008  			ordererProcesses[0].Signal(syscall.SIGTERM)
  1009  			Eventually(ordererProcesses[0].Wait(), network.EventuallyTimeout).Should(Receive())
  1010  
  1011  			By("Starting the evicted orderer again")
  1012  			ordererRunner = network.OrdererRunner(orderers[0])
  1013  			ordererRunners[0] = ordererRunner
  1014  			ordererProcesses[0] = ifrit.Invoke(ordererRunner)
  1015  			Eventually(ordererProcesses[0].Ready(), network.EventuallyTimeout).Should(BeClosed())
  1016  
  1017  			By("Ensuring the evicted orderer starts up marked the channel is inactive")
  1018  			Eventually(ordererRunner.Err(), time.Minute, time.Second).Should(gbytes.Say("Found 1 inactive chains"))
  1019  
  1020  			iDoNotBelong := "I do not belong to channel testchannel or am forbidden pulling it"
  1021  			Eventually(ordererRunner.Err(), time.Minute, time.Second).Should(gbytes.Say(iDoNotBelong))
  1022  
  1023  			By("Adding the evicted orderer back to the application channel")
  1024  			addConsenter(network, peer, o2, "testchannel", etcdraft.Consenter{
  1025  				ServerTlsCert: certificatesOfOrderers[0].oldCert,
  1026  				ClientTlsCert: certificatesOfOrderers[0].oldCert,
  1027  				Host:          "127.0.0.1",
  1028  				Port:          uint32(network.OrdererPort(orderers[0], nwo.ClusterPort)),
  1029  			})
  1030  
  1031  			By("Ensuring the re-added orderer joins the Raft cluster")
  1032  			findLeader([]*ginkgomon.Runner{ordererRunner})
  1033  		})
  1034  	})
  1035  
  1036  	When("an orderer node is joined", func() {
  1037  		It("isn't influenced by outdated orderers", func() {
  1038  			// This test checks that if a lagged is not aware of newly added nodes,
  1039  			// among which leader is present, it eventually pulls config block from
  1040  			// the orderer it knows, gets the certificates from it and participate
  1041  			// in consensus again.
  1042  			//
  1043  			// Steps:
  1044  			// Initial nodes in cluster: <1, 2, 3, 4>
  1045  			// - start <1, 2, 3>
  1046  			// - add <5, 6, 7>, start <5, 6, 7>
  1047  			// - kill <1>
  1048  			// - submit a tx, so that Raft index on <1> is behind <5, 6, 7> and <2, 3>
  1049  			// - kill <2, 3>
  1050  			// - start <1> and <4>. Since <1> is behind <5, 6, 7>, leader is certainly
  1051  			//   going to be elected from <5, 6, 7>
  1052  			// - assert that even <4> is not aware of leader, it can pull config block
  1053  			//   from <1>, and start participating in consensus.
  1054  
  1055  			orderers := make([]*nwo.Orderer, 7)
  1056  			ordererRunners = make([]*ginkgomon.Runner, 7)
  1057  			ordererProcesses = make([]ifrit.Process, 7)
  1058  
  1059  			for i := range orderers {
  1060  				orderers[i] = &nwo.Orderer{
  1061  					Name:         fmt.Sprintf("orderer%d", i+1),
  1062  					Organization: "OrdererOrg",
  1063  				}
  1064  			}
  1065  
  1066  			layout := nwo.MultiNodeEtcdRaft()
  1067  			layout.Orderers = orderers[:4]
  1068  			layout.Profiles[0].Orderers = []string{"orderer1", "orderer2", "orderer3", "orderer4"}
  1069  
  1070  			network = nwo.New(layout, testDir, client, StartPort(), components)
  1071  			network.GenerateConfigTree()
  1072  			network.Bootstrap()
  1073  
  1074  			peer = network.Peer("Org1", "peer1")
  1075  
  1076  			launch := func(i int) {
  1077  				runner := network.OrdererRunner(orderers[i])
  1078  				ordererRunners[i] = runner
  1079  				process := ifrit.Invoke(runner)
  1080  				Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
  1081  				ordererProcesses[i] = process
  1082  			}
  1083  
  1084  			By("Launching 3 out of 4 orderers")
  1085  			for i := range orderers[:3] {
  1086  				launch(i)
  1087  			}
  1088  
  1089  			leader := findLeader(ordererRunners[:3])
  1090  
  1091  			By("Checking that all orderers are online")
  1092  			assertBlockReception(map[string]int{
  1093  				"systemchannel": 0,
  1094  			}, orderers[:3], peer, network)
  1095  
  1096  			By("Configuring orderer[5, 6, 7] in the network")
  1097  			extendNetwork(network)
  1098  
  1099  			for _, o := range orderers[4:7] {
  1100  				ports := nwo.Ports{}
  1101  				for _, portName := range nwo.OrdererPortNames() {
  1102  					ports[portName] = network.ReservePort()
  1103  				}
  1104  				network.PortsByOrdererID[o.ID()] = ports
  1105  
  1106  				network.Orderers = append(network.Orderers, o)
  1107  				network.GenerateOrdererConfig(o)
  1108  			}
  1109  
  1110  			// Backup previous system channel block
  1111  			genesisBootBlock, err := ioutil.ReadFile(filepath.Join(testDir, "systemchannel_block.pb"))
  1112  			Expect(err).NotTo(HaveOccurred())
  1113  			restoreBootBlock := func() {
  1114  				err = ioutil.WriteFile(filepath.Join(testDir, "systemchannel_block.pb"), genesisBootBlock, 0644)
  1115  				Expect(err).NotTo(HaveOccurred())
  1116  			}
  1117  
  1118  			blockSeq := 0 // there's only one block in channel - genesis
  1119  			for _, i := range []int{4, 5, 6} {
  1120  				By(fmt.Sprintf("Adding orderer%d", i+1))
  1121  				ordererCertificatePath := filepath.Join(network.OrdererLocalTLSDir(orderers[i]), "server.crt")
  1122  				ordererCertificate, err := ioutil.ReadFile(ordererCertificatePath)
  1123  				Expect(err).NotTo(HaveOccurred())
  1124  
  1125  				addConsenter(network, peer, orderers[0], "systemchannel", etcdraft.Consenter{
  1126  					ServerTlsCert: ordererCertificate,
  1127  					ClientTlsCert: ordererCertificate,
  1128  					Host:          "127.0.0.1",
  1129  					Port:          uint32(network.OrdererPort(orderers[i], nwo.ClusterPort)),
  1130  				})
  1131  				blockSeq++
  1132  
  1133  				// Get the last config block of the system channel
  1134  				configBlock := nwo.GetConfigBlock(network, peer, orderers[0], "systemchannel")
  1135  				// Plant it in the file system of orderer, the new node to be onboarded.
  1136  				err = ioutil.WriteFile(filepath.Join(testDir, "systemchannel_block.pb"), protoutil.MarshalOrPanic(configBlock), 0644)
  1137  				Expect(err).NotTo(HaveOccurred())
  1138  
  1139  				By(fmt.Sprintf("Launching orderer%d", i+1))
  1140  				launch(i)
  1141  
  1142  				By(fmt.Sprintf("Checking that orderer%d has onboarded the network", i+1))
  1143  				assertBlockReception(map[string]int{
  1144  					"systemchannel": blockSeq,
  1145  				}, []*nwo.Orderer{orderers[i]}, peer, network)
  1146  			}
  1147  
  1148  			Expect(findLeader(ordererRunners[4:])).To(Equal(leader))
  1149  
  1150  			// Later on, when we start [1, 4, 5, 6, 7], we want to make sure that leader
  1151  			// is elected from [5, 6, 7], who are unknown to [4]. So we can assert that
  1152  			// [4] suspects its own eviction, pulls block from [1], and join the cluster.
  1153  			// Otherwise, if [1] is elected, and all other nodes already knew it, [4] may
  1154  			// simply replicate missing blocks with Raft, instead of pulling from others
  1155  			// triggered by eviction suspector.
  1156  
  1157  			By("Killing orderer1")
  1158  			ordererProcesses[0].Signal(syscall.SIGTERM)
  1159  			Eventually(ordererProcesses[0].Wait(), network.EventuallyTimeout).Should(Receive())
  1160  
  1161  			By("Submitting another tx to increment Raft index on alive orderers")
  1162  			if leader == 1 {
  1163  				// if orderer1 was leader, we should expect a new leader being elected before going forward
  1164  				findLeader([]*ginkgomon.Runner{ordererRunners[4]})
  1165  			}
  1166  
  1167  			env := CreateBroadcastEnvelope(network, orderers[4], network.SystemChannel.Name, []byte("hello"))
  1168  			resp, err := nwo.Broadcast(network, orderers[4], env)
  1169  			Expect(err).NotTo(HaveOccurred())
  1170  			Expect(resp.Status).To(Equal(common.Status_SUCCESS))
  1171  			blockSeq++
  1172  
  1173  			assertBlockReception(map[string]int{
  1174  				"systemchannel": blockSeq,
  1175  			}, []*nwo.Orderer{orderers[1], orderers[2], orderers[4], orderers[5], orderers[6]}, peer, network) // alive orderers: 2, 3, 5, 6, 7
  1176  
  1177  			By("Killing orderer[2,3]")
  1178  			for _, i := range []int{1, 2} {
  1179  				ordererProcesses[i].Signal(syscall.SIGTERM)
  1180  				Eventually(ordererProcesses[i].Wait(), network.EventuallyTimeout).Should(Receive())
  1181  			}
  1182  
  1183  			By("Launching the orderer that was never started")
  1184  			restoreBootBlock()
  1185  			launch(3)
  1186  
  1187  			By("Launching orderer1")
  1188  			launch(0)
  1189  
  1190  			By("Waiting until it suspects its eviction from the channel")
  1191  			Eventually(ordererRunners[3].Err(), time.Minute, time.Second).Should(gbytes.Say("Suspecting our own eviction from the channel"))
  1192  
  1193  			By("Making sure 4/7 orderers form quorum and serve request")
  1194  			assertBlockReception(map[string]int{
  1195  				"systemchannel": blockSeq,
  1196  			}, []*nwo.Orderer{orderers[3], orderers[4], orderers[5], orderers[6]}, peer, network) // alive orderers: 4, 5, 6, 7
  1197  		})
  1198  	})
  1199  
  1200  	It("can create a channel that contains a subset of orderers in system channel", func() {
  1201  		config := nwo.BasicEtcdRaft()
  1202  		config.Orderers = []*nwo.Orderer{
  1203  			{Name: "orderer1", Organization: "OrdererOrg"},
  1204  			{Name: "orderer2", Organization: "OrdererOrg"},
  1205  			{Name: "orderer3", Organization: "OrdererOrg"},
  1206  		}
  1207  		config.Profiles = []*nwo.Profile{{
  1208  			Name:     "SampleDevModeEtcdRaft",
  1209  			Orderers: []string{"orderer1", "orderer2", "orderer3"},
  1210  		}, {
  1211  			Name:          "ThreeOrdererChannel",
  1212  			Consortium:    "SampleConsortium",
  1213  			Organizations: []string{"Org1", "Org2"},
  1214  			Orderers:      []string{"orderer1", "orderer2", "orderer3"},
  1215  		}, {
  1216  			Name:          "SingleOrdererChannel",
  1217  			Consortium:    "SampleConsortium",
  1218  			Organizations: []string{"Org1", "Org2"},
  1219  			Orderers:      []string{"orderer1"},
  1220  		}}
  1221  		config.Channels = []*nwo.Channel{
  1222  			{Name: "single-orderer-channel", Profile: "SingleOrdererChannel", BaseProfile: "SampleDevModeEtcdRaft"},
  1223  			{Name: "three-orderer-channel", Profile: "ThreeOrdererChannel"},
  1224  		}
  1225  
  1226  		network = nwo.New(config, testDir, client, StartPort(), components)
  1227  		o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
  1228  		orderers := []*nwo.Orderer{o1, o2, o3}
  1229  		peer = network.Peer("Org1", "peer1")
  1230  
  1231  		network.GenerateConfigTree()
  1232  		network.Bootstrap()
  1233  
  1234  		By("Launching the orderers")
  1235  		for _, o := range orderers {
  1236  			runner := network.OrdererRunner(o)
  1237  			ordererRunners = append(ordererRunners, runner)
  1238  			process := ifrit.Invoke(runner)
  1239  			ordererProcesses = append(ordererProcesses, process)
  1240  		}
  1241  
  1242  		for _, ordererProc := range ordererProcesses {
  1243  			Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
  1244  		}
  1245  
  1246  		By("Creating an application channel with a subset of orderers in system channel")
  1247  		additionalPeer := network.Peer("Org2", "peer1")
  1248  		network.CreateChannel("single-orderer-channel", network.Orderers[0], peer, additionalPeer, network.Orderers[0])
  1249  
  1250  		By("Creating another channel via the orderer that is in system channel but not app channel")
  1251  		network.CreateChannel("three-orderer-channel", network.Orderers[2], peer)
  1252  	})
  1253  
  1254  	It("can add a new orderer organization", func() {
  1255  		network = nwo.New(nwo.MultiNodeEtcdRaft(), testDir, client, StartPort(), components)
  1256  		o1, o2, o3 := network.Orderer("orderer1"), network.Orderer("orderer2"), network.Orderer("orderer3")
  1257  		orderers := []*nwo.Orderer{o1, o2, o3}
  1258  
  1259  		network.GenerateConfigTree()
  1260  		network.Bootstrap()
  1261  
  1262  		By("Launching the orderers")
  1263  		for _, o := range orderers {
  1264  			runner := network.OrdererRunner(o)
  1265  			ordererRunners = append(ordererRunners, runner)
  1266  			process := ifrit.Invoke(runner)
  1267  			ordererProcesses = append(ordererProcesses, process)
  1268  		}
  1269  
  1270  		for _, ordererProc := range ordererProcesses {
  1271  			Eventually(ordererProc.Ready(), network.EventuallyTimeout).Should(BeClosed())
  1272  		}
  1273  
  1274  		By("Waiting for system channel to be ready")
  1275  		findLeader(ordererRunners)
  1276  
  1277  		peer := network.Peer("Org1", "peer1")
  1278  		channel := "systemchannel"
  1279  
  1280  		config := nwo.GetConfig(network, peer, o1, channel)
  1281  		updatedConfig := proto.Clone(config).(*common.Config)
  1282  
  1283  		ordererOrg := updatedConfig.ChannelGroup.Groups["Orderer"].Groups["OrdererOrg"]
  1284  		mspConfig := &msp.MSPConfig{}
  1285  		proto.Unmarshal(ordererOrg.Values["MSP"].Value, mspConfig)
  1286  
  1287  		fabMSPConfig := &msp.FabricMSPConfig{}
  1288  		proto.Unmarshal(mspConfig.Config, fabMSPConfig)
  1289  
  1290  		fabMSPConfig.Name = "OrdererMSP2"
  1291  
  1292  		mspConfig.Config, _ = proto.Marshal(fabMSPConfig)
  1293  		updatedConfig.ChannelGroup.Groups["Orderer"].Groups["OrdererMSP2"] = &common.ConfigGroup{
  1294  			Values: map[string]*common.ConfigValue{
  1295  				"MSP": {
  1296  					Value:     protoutil.MarshalOrPanic(mspConfig),
  1297  					ModPolicy: "Admins",
  1298  				},
  1299  			},
  1300  			ModPolicy: "Admins",
  1301  		}
  1302  
  1303  		nwo.UpdateOrdererConfig(network, o1, channel, config, updatedConfig, peer, o1)
  1304  	})
  1305  })
  1306  
  1307  func ensureEvicted(evictedOrderer *nwo.Orderer, submitter *nwo.Peer, network *nwo.Network, channel string) {
  1308  	c := commands.ChannelFetch{
  1309  		ChannelID:  channel,
  1310  		Block:      "newest",
  1311  		OutputFile: "/dev/null",
  1312  		Orderer:    network.OrdererAddress(evictedOrderer, nwo.ListenPort),
  1313  	}
  1314  
  1315  	sess, err := network.OrdererAdminSession(evictedOrderer, submitter, c)
  1316  	Expect(err).NotTo(HaveOccurred())
  1317  
  1318  	Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
  1319  	Expect(sess.Err).To(gbytes.Say("SERVICE_UNAVAILABLE"))
  1320  }
  1321  
  1322  var extendedCryptoConfig = `---
  1323  OrdererOrgs:
  1324  - Name: OrdererOrg
  1325    Domain: example.com
  1326    EnableNodeOUs: false
  1327    CA:
  1328      Hostname: ca
  1329    Specs:
  1330    - Hostname: orderer1
  1331      SANS:
  1332      - localhost
  1333      - 127.0.0.1
  1334      - ::1
  1335    - Hostname: orderer1new
  1336      SANS:
  1337      - localhost
  1338      - 127.0.0.1
  1339      - ::1
  1340    - Hostname: orderer2
  1341      SANS:
  1342      - localhost
  1343      - 127.0.0.1
  1344      - ::1
  1345    - Hostname: orderer2new
  1346      SANS:
  1347      - localhost
  1348      - 127.0.0.1
  1349      - ::1
  1350    - Hostname: orderer3
  1351      SANS:
  1352      - localhost
  1353      - 127.0.0.1
  1354      - ::1
  1355    - Hostname: orderer3new
  1356      SANS:
  1357      - localhost
  1358      - 127.0.0.1
  1359      - ::1
  1360    - Hostname: orderer4
  1361      SANS:
  1362      - localhost
  1363      - 127.0.0.1
  1364      - ::1
  1365    - Hostname: orderer5
  1366      SANS:
  1367      - localhost
  1368      - 127.0.0.1
  1369      - ::1
  1370    - Hostname: orderer6
  1371      SANS:
  1372      - localhost
  1373      - 127.0.0.1
  1374      - ::1
  1375    - Hostname: orderer7
  1376      SANS:
  1377      - localhost
  1378      - 127.0.0.1
  1379      - ::1
  1380  `
  1381  
  1382  type certificateChange struct {
  1383  	srcFile string
  1384  	dstFile string
  1385  	oldCert []byte
  1386  	oldKey  []byte
  1387  	newCert []byte
  1388  }
  1389  
  1390  // extendNetwork rotates adds an additional orderer
  1391  func extendNetwork(n *nwo.Network) {
  1392  	// Overwrite the current crypto-config with additional orderers
  1393  	cryptoConfigYAML, err := ioutil.TempFile("", "crypto-config.yaml")
  1394  	Expect(err).NotTo(HaveOccurred())
  1395  	defer os.Remove(cryptoConfigYAML.Name())
  1396  
  1397  	err = ioutil.WriteFile(cryptoConfigYAML.Name(), []byte(extendedCryptoConfig), 0644)
  1398  	Expect(err).NotTo(HaveOccurred())
  1399  
  1400  	// Invoke cryptogen extend to add new orderers
  1401  	sess, err := n.Cryptogen(commands.Extend{
  1402  		Config: cryptoConfigYAML.Name(),
  1403  		Input:  n.CryptoPath(),
  1404  	})
  1405  	Expect(err).NotTo(HaveOccurred())
  1406  	Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
  1407  }
  1408  
  1409  // refreshOrdererPEMs rotates all TLS certificates of all nodes,
  1410  // and returns the deltas
  1411  func refreshOrdererPEMs(n *nwo.Network) []*certificateChange {
  1412  	var fileChanges []*certificateChange
  1413  	// Populate source to destination files
  1414  	err := filepath.Walk(n.CryptoPath(), func(path string, info os.FileInfo, err error) error {
  1415  		if !strings.Contains(path, "/tls/") {
  1416  			return nil
  1417  		}
  1418  		if strings.Contains(path, "new") {
  1419  			fileChanges = append(fileChanges, &certificateChange{
  1420  				srcFile: path,
  1421  				dstFile: strings.Replace(path, "new", "", -1),
  1422  			})
  1423  		}
  1424  		return nil
  1425  	})
  1426  	Expect(err).NotTo(HaveOccurred())
  1427  
  1428  	var serverCertChanges []*certificateChange
  1429  
  1430  	// Overwrite the destination files with the contents of the source files.
  1431  	for _, certChange := range fileChanges {
  1432  		previousCertBytes, err := ioutil.ReadFile(certChange.dstFile)
  1433  		Expect(err).NotTo(HaveOccurred())
  1434  
  1435  		newCertBytes, err := ioutil.ReadFile(certChange.srcFile)
  1436  		Expect(err).NotTo(HaveOccurred())
  1437  
  1438  		err = ioutil.WriteFile(certChange.dstFile, newCertBytes, 0644)
  1439  		Expect(err).NotTo(HaveOccurred())
  1440  
  1441  		if !strings.Contains(certChange.dstFile, "server.crt") {
  1442  			continue
  1443  		}
  1444  
  1445  		// Read the previous key file
  1446  		previousKeyBytes, err := ioutil.ReadFile(strings.Replace(certChange.dstFile, "server.crt", "server.key", -1))
  1447  		Expect(err).NotTo(HaveOccurred())
  1448  
  1449  		serverCertChanges = append(serverCertChanges, certChange)
  1450  		certChange.newCert = newCertBytes
  1451  		certChange.oldCert = previousCertBytes
  1452  		certChange.oldKey = previousKeyBytes
  1453  	}
  1454  	return serverCertChanges
  1455  }
  1456  
  1457  // assertBlockReception asserts that the given orderers have expected heights for the given channel--> height mapping
  1458  func assertBlockReception(expectedHeightsPerChannel map[string]int, orderers []*nwo.Orderer, p *nwo.Peer, n *nwo.Network) {
  1459  	assertReception := func(channelName string, blockSeq int) {
  1460  		var wg sync.WaitGroup
  1461  		wg.Add(len(orderers))
  1462  		for _, orderer := range orderers {
  1463  			go func(orderer *nwo.Orderer) {
  1464  				defer GinkgoRecover()
  1465  				defer wg.Done()
  1466  				waitForBlockReception(orderer, p, n, channelName, blockSeq)
  1467  			}(orderer)
  1468  		}
  1469  		wg.Wait()
  1470  	}
  1471  
  1472  	var wg sync.WaitGroup
  1473  	wg.Add(len(expectedHeightsPerChannel))
  1474  
  1475  	for channelName, blockSeq := range expectedHeightsPerChannel {
  1476  		go func(channelName string, blockSeq int) {
  1477  			defer GinkgoRecover()
  1478  			defer wg.Done()
  1479  			assertReception(channelName, blockSeq)
  1480  		}(channelName, blockSeq)
  1481  	}
  1482  	wg.Wait()
  1483  }
  1484  
  1485  func waitForBlockReception(o *nwo.Orderer, submitter *nwo.Peer, network *nwo.Network, channelName string, blockSeq int) {
  1486  	c := commands.ChannelFetch{
  1487  		ChannelID:  channelName,
  1488  		Block:      "newest",
  1489  		OutputFile: "/dev/null",
  1490  		Orderer:    network.OrdererAddress(o, nwo.ListenPort),
  1491  	}
  1492  	Eventually(func() string {
  1493  		sess, err := network.OrdererAdminSession(o, submitter, c)
  1494  		Expect(err).NotTo(HaveOccurred())
  1495  		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
  1496  		if sess.ExitCode() != 0 {
  1497  			return fmt.Sprintf("exit code is %d: %s", sess.ExitCode(), string(sess.Err.Contents()))
  1498  		}
  1499  		sessErr := string(sess.Err.Contents())
  1500  		expected := fmt.Sprintf("Received block: %d", blockSeq)
  1501  		if strings.Contains(sessErr, expected) {
  1502  			return ""
  1503  		}
  1504  		return sessErr
  1505  	}, network.EventuallyTimeout, time.Second).Should(BeEmpty())
  1506  }
  1507  
  1508  func revokeReaderAccess(network *nwo.Network, channel string, orderer *nwo.Orderer, peer *nwo.Peer) {
  1509  	config := nwo.GetConfig(network, peer, orderer, channel)
  1510  	updatedConfig := proto.Clone(config).(*common.Config)
  1511  
  1512  	// set the policy
  1513  	adminPolicy := protoutil.MarshalOrPanic(&common.ImplicitMetaPolicy{
  1514  		SubPolicy: "Admins",
  1515  		Rule:      common.ImplicitMetaPolicy_MAJORITY,
  1516  	})
  1517  	updatedConfig.ChannelGroup.Groups["Orderer"].Policies["Readers"].Policy.Value = adminPolicy
  1518  	nwo.UpdateOrdererConfig(network, orderer, channel, config, updatedConfig, peer, orderer)
  1519  }
  1520  
  1521  // consenterAdder constructs configs that can be used by `UpdateOrdererConfig`
  1522  // to add a consenter.
  1523  func consenterAdder(n *nwo.Network, peer *nwo.Peer, orderer *nwo.Orderer, channel string, consenter etcdraft.Consenter) (current, updated *common.Config) {
  1524  	config := nwo.GetConfig(n, peer, orderer, channel)
  1525  	updatedConfig := proto.Clone(config).(*common.Config)
  1526  
  1527  	consensusTypeConfigValue := updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"]
  1528  	consensusTypeValue := &protosorderer.ConsensusType{}
  1529  	err := proto.Unmarshal(consensusTypeConfigValue.Value, consensusTypeValue)
  1530  	Expect(err).NotTo(HaveOccurred())
  1531  
  1532  	metadata := &etcdraft.ConfigMetadata{}
  1533  	err = proto.Unmarshal(consensusTypeValue.Metadata, metadata)
  1534  	Expect(err).NotTo(HaveOccurred())
  1535  
  1536  	metadata.Consenters = append(metadata.Consenters, &consenter)
  1537  
  1538  	consensusTypeValue.Metadata, err = proto.Marshal(metadata)
  1539  	Expect(err).NotTo(HaveOccurred())
  1540  
  1541  	updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"] = &common.ConfigValue{
  1542  		ModPolicy: "Admins",
  1543  		Value:     protoutil.MarshalOrPanic(consensusTypeValue),
  1544  	}
  1545  
  1546  	return config, updatedConfig
  1547  }
  1548  
  1549  // consenterRemover constructs configs that can be used by
  1550  // `UpdateOrdererConfig` to remove a consenter.
  1551  func consenterRemover(n *nwo.Network, peer *nwo.Peer, orderer *nwo.Orderer, channel string, certificate []byte) (current, updated *common.Config) {
  1552  	config := nwo.GetConfig(n, peer, orderer, channel)
  1553  	updatedConfig := proto.Clone(config).(*common.Config)
  1554  
  1555  	consensusTypeConfigValue := updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"]
  1556  	consensusTypeValue := &protosorderer.ConsensusType{}
  1557  	err := proto.Unmarshal(consensusTypeConfigValue.Value, consensusTypeValue)
  1558  	Expect(err).NotTo(HaveOccurred())
  1559  
  1560  	metadata := &etcdraft.ConfigMetadata{}
  1561  	err = proto.Unmarshal(consensusTypeValue.Metadata, metadata)
  1562  	Expect(err).NotTo(HaveOccurred())
  1563  
  1564  	var newConsenters []*etcdraft.Consenter
  1565  	for _, consenter := range metadata.Consenters {
  1566  		if bytes.Equal(consenter.ClientTlsCert, certificate) || bytes.Equal(consenter.ServerTlsCert, certificate) {
  1567  			continue
  1568  		}
  1569  		newConsenters = append(newConsenters, consenter)
  1570  	}
  1571  
  1572  	metadata.Consenters = newConsenters
  1573  	consensusTypeValue.Metadata, err = proto.Marshal(metadata)
  1574  	Expect(err).NotTo(HaveOccurred())
  1575  
  1576  	updatedConfig.ChannelGroup.Groups["Orderer"].Values["ConsensusType"] = &common.ConfigValue{
  1577  		ModPolicy: "Admins",
  1578  		Value:     protoutil.MarshalOrPanic(consensusTypeValue),
  1579  	}
  1580  
  1581  	return config, updatedConfig
  1582  }
  1583  
  1584  // addConsenter adds a new consenter to the given channel.
  1585  func addConsenter(n *nwo.Network, peer *nwo.Peer, orderer *nwo.Orderer, channel string, consenter etcdraft.Consenter) {
  1586  	updateEtcdRaftMetadata(n, peer, orderer, channel, func(metadata *etcdraft.ConfigMetadata) {
  1587  		metadata.Consenters = append(metadata.Consenters, &consenter)
  1588  	})
  1589  }
  1590  
  1591  // removeConsenter removes a consenter with the given certificate in PEM format
  1592  // from the given channel.
  1593  func removeConsenter(n *nwo.Network, peer *nwo.Peer, orderer *nwo.Orderer, channel string, certificate []byte) {
  1594  	updateEtcdRaftMetadata(n, peer, orderer, channel, func(metadata *etcdraft.ConfigMetadata) {
  1595  		var newConsenters []*etcdraft.Consenter
  1596  		for _, consenter := range metadata.Consenters {
  1597  			if bytes.Equal(consenter.ClientTlsCert, certificate) || bytes.Equal(consenter.ServerTlsCert, certificate) {
  1598  				continue
  1599  			}
  1600  			newConsenters = append(newConsenters, consenter)
  1601  		}
  1602  
  1603  		metadata.Consenters = newConsenters
  1604  	})
  1605  }
  1606  
  1607  // updateEtcdRaftMetadata executes a config update that updates the etcdraft
  1608  // metadata according to the given function f.
  1609  func updateEtcdRaftMetadata(network *nwo.Network, peer *nwo.Peer, orderer *nwo.Orderer, channel string, f func(md *etcdraft.ConfigMetadata)) {
  1610  	nwo.UpdateConsensusMetadata(network, peer, orderer, channel, func(originalMetadata []byte) []byte {
  1611  		metadata := &etcdraft.ConfigMetadata{}
  1612  		err := proto.Unmarshal(originalMetadata, metadata)
  1613  		Expect(err).NotTo(HaveOccurred())
  1614  
  1615  		f(metadata)
  1616  
  1617  		newMetadata, err := proto.Marshal(metadata)
  1618  		Expect(err).NotTo(HaveOccurred())
  1619  		return newMetadata
  1620  	})
  1621  }