github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/server/main_test.go (about)

     1  // Copyright hechain. All Rights Reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package server
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"net/http"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/golang/protobuf/proto"
    20  	"github.com/hechain20/hechain/bccsp"
    21  	"github.com/hechain20/hechain/bccsp/factory"
    22  	"github.com/hechain20/hechain/bccsp/sw"
    23  	"github.com/hechain20/hechain/common/channelconfig"
    24  	"github.com/hechain20/hechain/common/crypto/tlsgen"
    25  	"github.com/hechain20/hechain/common/flogging"
    26  	"github.com/hechain20/hechain/common/flogging/floggingtest"
    27  	"github.com/hechain20/hechain/common/ledger/blockledger"
    28  	"github.com/hechain20/hechain/common/ledger/blockledger/fileledger"
    29  	"github.com/hechain20/hechain/common/metrics/disabled"
    30  	"github.com/hechain20/hechain/common/metrics/prometheus"
    31  	"github.com/hechain20/hechain/core/config/configtest"
    32  	"github.com/hechain20/hechain/internal/configtxgen/encoder"
    33  	"github.com/hechain20/hechain/internal/configtxgen/genesisconfig"
    34  	"github.com/hechain20/hechain/internal/pkg/comm"
    35  	"github.com/hechain20/hechain/internal/pkg/identity"
    36  	"github.com/hechain20/hechain/orderer/common/bootstrap/file"
    37  	"github.com/hechain20/hechain/orderer/common/cluster"
    38  	"github.com/hechain20/hechain/orderer/common/filerepo"
    39  	"github.com/hechain20/hechain/orderer/common/localconfig"
    40  	"github.com/hechain20/hechain/orderer/common/multichannel"
    41  	"github.com/hechain20/hechain/orderer/common/onboarding"
    42  	server_mocks "github.com/hechain20/hechain/orderer/common/server/mocks"
    43  	"github.com/hechain20/hechain/orderer/consensus"
    44  	"github.com/hechain20/hechain/protoutil"
    45  	"github.com/hyperledger/fabric-protos-go/common"
    46  	. "github.com/onsi/gomega"
    47  	"github.com/onsi/gomega/gexec"
    48  	"github.com/pkg/errors"
    49  	"github.com/stretchr/testify/require"
    50  	"go.uber.org/zap"
    51  	"go.uber.org/zap/zapcore"
    52  )
    53  
    54  //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    55  
    56  type signerSerializer interface {
    57  	identity.SignerSerializer
    58  }
    59  
    60  // the path to cryptogen, which can be used by tests to create certificates
    61  var cryptogen, tempDir string
    62  
    63  func TestMain(m *testing.M) {
    64  	var err error
    65  	cryptogen, err = gexec.Build("github.com/hechain20/hechain/cmd/cryptogen")
    66  	if err != nil {
    67  		fmt.Fprintf(os.Stderr, "cryptogen build failed: %v", err)
    68  		os.Exit(-1)
    69  	}
    70  	defer gexec.CleanupBuildArtifacts()
    71  
    72  	tempDir, err = ioutil.TempDir("", "main-test")
    73  	if err != nil {
    74  		fmt.Fprintf(os.Stderr, "failed to create temporary directory: %v", err)
    75  		os.Exit(-1)
    76  	}
    77  	defer os.RemoveAll(tempDir)
    78  
    79  	copyYamlFiles("testdata", tempDir)
    80  
    81  	os.Exit(m.Run())
    82  }
    83  
    84  func copyYamlFiles(src, dst string) {
    85  	for _, file := range []string{"configtx.yaml", "examplecom-config.yaml", "orderer.yaml"} {
    86  		fileBytes, err := ioutil.ReadFile(filepath.Join(src, file))
    87  		if err != nil {
    88  			os.Exit(-1)
    89  		}
    90  		err = ioutil.WriteFile(filepath.Join(dst, file), fileBytes, 0o644)
    91  		if err != nil {
    92  			os.Exit(-1)
    93  		}
    94  	}
    95  }
    96  
    97  func TestInitializeLogging(t *testing.T) {
    98  	origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC")
    99  	os.Setenv("FABRIC_LOGGING_SPEC", "foo=debug")
   100  	initializeLogging()
   101  	require.Equal(t, "debug", flogging.LoggerLevel("foo"))
   102  	os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue)
   103  }
   104  
   105  func TestInitializeProfilingService(t *testing.T) {
   106  	origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC")
   107  	defer os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue)
   108  	os.Setenv("FABRIC_LOGGING_SPEC", "debug")
   109  	// get a free random port
   110  	listenAddr := func() string {
   111  		l, _ := net.Listen("tcp", "localhost:0")
   112  		l.Close()
   113  		return l.Addr().String()
   114  	}()
   115  	go initializeProfilingService(
   116  		&localconfig.TopLevel{
   117  			General: localconfig.General{
   118  				Profile: localconfig.Profile{
   119  					Enabled: true,
   120  					Address: listenAddr,
   121  				},
   122  			},
   123  			Kafka: localconfig.Kafka{Verbose: true},
   124  		},
   125  	)
   126  	time.Sleep(500 * time.Millisecond)
   127  	if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil {
   128  		t.Logf("Expected pprof to be up (will retry again in 3 seconds): %s", err)
   129  		time.Sleep(3 * time.Second)
   130  		if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil {
   131  			t.Fatalf("Expected pprof to be up: %s", err)
   132  		}
   133  	}
   134  }
   135  
   136  func TestInitializeServerConfig(t *testing.T) {
   137  	conf := &localconfig.TopLevel{
   138  		General: localconfig.General{
   139  			ConnectionTimeout: 7 * time.Second,
   140  			TLS: localconfig.TLS{
   141  				Enabled:            true,
   142  				ClientAuthRequired: true,
   143  				Certificate:        "main.go",
   144  				PrivateKey:         "main.go",
   145  				RootCAs:            []string{"main.go"},
   146  				ClientRootCAs:      []string{"main.go"},
   147  			},
   148  		},
   149  	}
   150  	sc := initializeServerConfig(conf, nil)
   151  	expectedContent, _ := ioutil.ReadFile("main.go")
   152  	require.Equal(t, expectedContent, sc.SecOpts.Certificate)
   153  	require.Equal(t, expectedContent, sc.SecOpts.Key)
   154  	require.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ServerRootCAs)
   155  	require.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ClientRootCAs)
   156  
   157  	sc = initializeServerConfig(conf, nil)
   158  	defaultOpts := comm.DefaultKeepaliveOptions
   159  	require.Equal(t, defaultOpts.ServerMinInterval, sc.KaOpts.ServerMinInterval)
   160  	require.Equal(t, time.Duration(0), sc.KaOpts.ServerInterval)
   161  	require.Equal(t, time.Duration(0), sc.KaOpts.ServerTimeout)
   162  	require.Equal(t, 7*time.Second, sc.ConnectionTimeout)
   163  	testDuration := 10 * time.Second
   164  	conf.General.Keepalive = localconfig.Keepalive{
   165  		ServerMinInterval: testDuration,
   166  		ServerInterval:    testDuration,
   167  		ServerTimeout:     testDuration,
   168  	}
   169  	sc = initializeServerConfig(conf, nil)
   170  	require.Equal(t, testDuration, sc.KaOpts.ServerMinInterval)
   171  	require.Equal(t, testDuration, sc.KaOpts.ServerInterval)
   172  	require.Equal(t, testDuration, sc.KaOpts.ServerTimeout)
   173  
   174  	sc = initializeServerConfig(conf, nil)
   175  	require.NotNil(t, sc.Logger)
   176  	require.Equal(t, comm.NewServerStatsHandler(&disabled.Provider{}), sc.ServerStatsHandler)
   177  	require.Len(t, sc.UnaryInterceptors, 2)
   178  	require.Len(t, sc.StreamInterceptors, 2)
   179  
   180  	sc = initializeServerConfig(conf, &prometheus.Provider{})
   181  	require.NotNil(t, sc.ServerStatsHandler)
   182  
   183  	goodFile := "main.go"
   184  	badFile := "does_not_exist"
   185  
   186  	oldLogger := logger
   187  	defer func() { logger = oldLogger }()
   188  	logger, _ = floggingtest.NewTestLogger(t)
   189  
   190  	testCases := []struct {
   191  		name           string
   192  		certificate    string
   193  		privateKey     string
   194  		rootCA         string
   195  		clientRootCert string
   196  		clusterCert    string
   197  		clusterKey     string
   198  		clusterCA      string
   199  		isCluster      bool
   200  		expectedPanic  string
   201  	}{
   202  		{
   203  			name:           "BadCertificate",
   204  			certificate:    badFile,
   205  			privateKey:     goodFile,
   206  			rootCA:         goodFile,
   207  			clientRootCert: goodFile,
   208  			expectedPanic:  "Failed to load server Certificate file 'does_not_exist' (open does_not_exist: no such file or directory)",
   209  		},
   210  		{
   211  			name:           "BadPrivateKey",
   212  			certificate:    goodFile,
   213  			privateKey:     badFile,
   214  			rootCA:         goodFile,
   215  			clientRootCert: goodFile,
   216  			expectedPanic:  "Failed to load PrivateKey file 'does_not_exist' (open does_not_exist: no such file or directory)",
   217  		},
   218  		{
   219  			name:           "BadRootCA",
   220  			certificate:    goodFile,
   221  			privateKey:     goodFile,
   222  			rootCA:         badFile,
   223  			clientRootCert: goodFile,
   224  			expectedPanic:  "Failed to load ServerRootCAs file 'open does_not_exist: no such file or directory' (does_not_exist)",
   225  		},
   226  		{
   227  			name:           "BadClientRootCertificate",
   228  			certificate:    goodFile,
   229  			privateKey:     goodFile,
   230  			rootCA:         goodFile,
   231  			clientRootCert: badFile,
   232  			expectedPanic:  "Failed to load ClientRootCAs file 'open does_not_exist: no such file or directory' (does_not_exist)",
   233  		},
   234  		{
   235  			name:           "BadCertificate - cluster reuses server config",
   236  			certificate:    badFile,
   237  			privateKey:     goodFile,
   238  			rootCA:         goodFile,
   239  			clientRootCert: goodFile,
   240  			clusterCert:    "",
   241  			clusterKey:     "",
   242  			clusterCA:      "",
   243  			isCluster:      true,
   244  			expectedPanic:  "Failed to load client TLS certificate file 'does_not_exist' (open does_not_exist: no such file or directory)",
   245  		},
   246  		{
   247  			name:           "BadPrivateKey - cluster reuses server config",
   248  			certificate:    goodFile,
   249  			privateKey:     badFile,
   250  			rootCA:         goodFile,
   251  			clientRootCert: goodFile,
   252  			clusterCert:    "",
   253  			clusterKey:     "",
   254  			clusterCA:      "",
   255  			isCluster:      true,
   256  			expectedPanic:  "Failed to load client TLS key file 'does_not_exist' (open does_not_exist: no such file or directory)",
   257  		},
   258  		{
   259  			name:           "BadRootCA - cluster reuses server config",
   260  			certificate:    goodFile,
   261  			privateKey:     goodFile,
   262  			rootCA:         badFile,
   263  			clientRootCert: goodFile,
   264  			clusterCert:    "",
   265  			clusterKey:     "",
   266  			clusterCA:      "",
   267  			isCluster:      true,
   268  			expectedPanic:  "Failed to load ServerRootCAs file '' (open : no such file or directory)",
   269  		},
   270  		{
   271  			name:           "ClusterBadCertificate",
   272  			certificate:    goodFile,
   273  			privateKey:     goodFile,
   274  			rootCA:         goodFile,
   275  			clientRootCert: goodFile,
   276  			clusterCert:    badFile,
   277  			clusterKey:     goodFile,
   278  			clusterCA:      goodFile,
   279  			isCluster:      true,
   280  			expectedPanic:  "Failed to load client TLS certificate file 'does_not_exist' (open does_not_exist: no such file or directory)",
   281  		},
   282  		{
   283  			name:           "ClusterBadPrivateKey",
   284  			certificate:    goodFile,
   285  			privateKey:     goodFile,
   286  			rootCA:         goodFile,
   287  			clientRootCert: goodFile,
   288  			clusterCert:    goodFile,
   289  			clusterKey:     badFile,
   290  			clusterCA:      goodFile,
   291  			isCluster:      true,
   292  			expectedPanic:  "Failed to load client TLS key file 'does_not_exist' (open does_not_exist: no such file or directory)",
   293  		},
   294  		{
   295  			name:           "ClusterBadRootCA",
   296  			certificate:    goodFile,
   297  			privateKey:     goodFile,
   298  			rootCA:         goodFile,
   299  			clientRootCert: goodFile,
   300  			clusterCert:    goodFile,
   301  			clusterKey:     goodFile,
   302  			clusterCA:      badFile,
   303  			isCluster:      true,
   304  			expectedPanic:  "Failed to load ServerRootCAs file 'does_not_exist' (open does_not_exist: no such file or directory)",
   305  		},
   306  	}
   307  	for _, tc := range testCases {
   308  		t.Run(tc.name, func(t *testing.T) {
   309  			conf := &localconfig.TopLevel{
   310  				General: localconfig.General{
   311  					TLS: localconfig.TLS{
   312  						Enabled:            true,
   313  						ClientAuthRequired: true,
   314  						Certificate:        tc.certificate,
   315  						PrivateKey:         tc.privateKey,
   316  						RootCAs:            []string{tc.rootCA},
   317  						ClientRootCAs:      []string{tc.clientRootCert},
   318  					},
   319  					Cluster: localconfig.Cluster{
   320  						ClientCertificate: tc.clusterCert,
   321  						ClientPrivateKey:  tc.clusterKey,
   322  						RootCAs:           []string{tc.clusterCA},
   323  					},
   324  				},
   325  			}
   326  			require.PanicsWithValue(t, tc.expectedPanic, func() {
   327  				if !tc.isCluster {
   328  					initializeServerConfig(conf, nil)
   329  				} else {
   330  					initializeClusterClientConfig(conf)
   331  				}
   332  			},
   333  			)
   334  		})
   335  	}
   336  }
   337  
   338  func TestInitializeBootstrapChannel(t *testing.T) {
   339  	cleanup := configtest.SetDevFabricConfigPath(t)
   340  	defer cleanup()
   341  
   342  	genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid")
   343  	defer os.Remove(genesisFile)
   344  
   345  	fileLedgerLocation, _ := ioutil.TempDir("", "main_test-")
   346  	defer os.RemoveAll(fileLedgerLocation)
   347  
   348  	ledgerFactory, err := createLedgerFactory(
   349  		&localconfig.TopLevel{
   350  			FileLedger: localconfig.FileLedger{
   351  				Location: fileLedgerLocation,
   352  			},
   353  		},
   354  		&disabled.Provider{},
   355  	)
   356  	require.NoError(t, err)
   357  	bootstrapConfig := &localconfig.TopLevel{
   358  		General: localconfig.General{
   359  			BootstrapMethod: "file",
   360  			BootstrapFile:   genesisFile,
   361  		},
   362  	}
   363  
   364  	bootstrapBlock := extractBootstrapBlock(bootstrapConfig)
   365  	initializeBootstrapChannel(bootstrapBlock, ledgerFactory)
   366  
   367  	ledger, err := ledgerFactory.GetOrCreate("testchannelid")
   368  	require.NoError(t, err)
   369  	require.Equal(t, uint64(1), ledger.Height())
   370  }
   371  
   372  func TestExtractBootstrapBlock(t *testing.T) {
   373  	cleanup := configtest.SetDevFabricConfigPath(t)
   374  	defer cleanup()
   375  
   376  	genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid")
   377  	defer os.Remove(genesisFile)
   378  
   379  	tests := []struct {
   380  		config *localconfig.TopLevel
   381  		block  *common.Block
   382  	}{
   383  		{
   384  			config: &localconfig.TopLevel{
   385  				General: localconfig.General{BootstrapMethod: "file", BootstrapFile: genesisFile},
   386  			},
   387  			block: file.New(genesisFile).GenesisBlock(),
   388  		},
   389  		{
   390  			config: &localconfig.TopLevel{
   391  				General: localconfig.General{BootstrapMethod: "none"},
   392  			},
   393  			block: nil,
   394  		},
   395  	}
   396  	for _, tt := range tests {
   397  		b := extractBootstrapBlock(tt.config)
   398  		require.Truef(t, proto.Equal(tt.block, b), "wanted %v, got %v", tt.block, b)
   399  	}
   400  }
   401  
   402  func TestInitSystemChannelWithJoinBlock(t *testing.T) {
   403  	configPathCleanup := configtest.SetDevFabricConfigPath(t)
   404  	defer configPathCleanup()
   405  	genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid")
   406  	defer os.Remove(genesisFile)
   407  
   408  	var (
   409  		config         *localconfig.TopLevel
   410  		cryptoProvider bccsp.BCCSP
   411  		ledgerFactory  blockledger.Factory
   412  		fileRepo       *filerepo.Repo
   413  		genesisBytes   []byte
   414  	)
   415  
   416  	setup := func() func() {
   417  		fileLedgerLocation, err := ioutil.TempDir("", "main_test-")
   418  		require.NoError(t, err)
   419  
   420  		config = &localconfig.TopLevel{
   421  			General: localconfig.General{
   422  				BootstrapMethod: "none",
   423  			},
   424  			FileLedger: localconfig.FileLedger{
   425  				Location: fileLedgerLocation,
   426  			},
   427  			ChannelParticipation: localconfig.ChannelParticipation{Enabled: true},
   428  		}
   429  
   430  		cryptoProvider, err = sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   431  		require.NoError(t, err)
   432  
   433  		ledgerFactory, err = createLedgerFactory(config, &disabled.Provider{})
   434  		require.NoError(t, err)
   435  
   436  		fileRepo, err = multichannel.InitJoinBlockFileRepo(config)
   437  		require.NoError(t, err)
   438  		require.NotNil(t, fileRepo)
   439  
   440  		genesisBytes, err = ioutil.ReadFile(genesisFile)
   441  		require.NoError(t, err)
   442  		require.NotNil(t, genesisBytes)
   443  
   444  		return func() {
   445  			os.RemoveAll(fileLedgerLocation)
   446  		}
   447  	}
   448  
   449  	t.Run("No join-block", func(t *testing.T) {
   450  		cleanup := setup()
   451  		defer cleanup()
   452  
   453  		bootstrapBlock := initSystemChannelWithJoinBlock(config, cryptoProvider, ledgerFactory)
   454  		require.Nil(t, bootstrapBlock)
   455  		ledger, err := ledgerFactory.GetOrCreate("testchannelid")
   456  		require.NoError(t, err)
   457  		require.Equal(t, uint64(0), ledger.Height())
   458  	})
   459  
   460  	t.Run("With genesis join-block", func(t *testing.T) {
   461  		cleanup := setup()
   462  		defer cleanup()
   463  
   464  		err := fileRepo.Save("testchannelid", genesisBytes)
   465  		require.NoError(t, err)
   466  		bootstrapBlock := initSystemChannelWithJoinBlock(config, cryptoProvider, ledgerFactory)
   467  		require.NotNil(t, bootstrapBlock)
   468  		ledger, err := ledgerFactory.GetOrCreate("testchannelid")
   469  		require.NoError(t, err)
   470  		require.Equal(t, uint64(1), ledger.Height())
   471  		// Again, ledger already exists
   472  		bootstrapBlock = initSystemChannelWithJoinBlock(config, cryptoProvider, ledgerFactory)
   473  		require.NotNil(t, bootstrapBlock)
   474  		ledger, err = ledgerFactory.GetOrCreate("testchannelid")
   475  		require.NoError(t, err)
   476  		require.Equal(t, uint64(1), ledger.Height())
   477  	})
   478  
   479  	t.Run("With non-genesis join-block", func(t *testing.T) {
   480  		cleanup := setup()
   481  		defer cleanup()
   482  
   483  		block := protoutil.UnmarshalBlockOrPanic(genesisBytes)
   484  		block.Header.Number = 7
   485  		configBlockBytes := protoutil.MarshalOrPanic(block)
   486  		err := fileRepo.Save("testchannelid", configBlockBytes)
   487  		require.NoError(t, err)
   488  		bootstrapBlock := initSystemChannelWithJoinBlock(config, cryptoProvider, ledgerFactory)
   489  		require.NotNil(t, bootstrapBlock)
   490  		ledger, err := ledgerFactory.GetOrCreate("testchannelid")
   491  		require.NoError(t, err)
   492  		require.Equal(t, uint64(0), ledger.Height())
   493  	})
   494  }
   495  
   496  func TestExtractSystemChannel(t *testing.T) {
   497  	cryptoProvider, _ := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   498  
   499  	tmpdir, err := ioutil.TempDir("", "main_test-")
   500  	require.NoError(t, err)
   501  	defer os.RemoveAll(tmpdir)
   502  
   503  	rlf, err := fileledger.New(tmpdir, &disabled.Provider{})
   504  	require.NoError(t, err)
   505  
   506  	lastConf := extractSystemChannel(rlf, cryptoProvider)
   507  	require.Nil(t, lastConf, "no ledgers")
   508  
   509  	_, err = rlf.GetOrCreate("emptychannelid")
   510  	require.NoError(t, err)
   511  
   512  	lastConf = extractSystemChannel(rlf, cryptoProvider)
   513  	require.Nil(t, lastConf, "skip empty ledger")
   514  
   515  	conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   516  	conf.Consortiums = nil
   517  	configBlock := encoder.New(conf).GenesisBlock()
   518  	rl, err := rlf.GetOrCreate("appchannelid")
   519  	require.NoError(t, err)
   520  	err = rl.Append(configBlock)
   521  	require.NoError(t, err)
   522  
   523  	lastConf = extractSystemChannel(rlf, cryptoProvider)
   524  	require.Nil(t, lastConf, "skip app ledger")
   525  
   526  	conf = genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   527  	configBlock = encoder.New(conf).GenesisBlock()
   528  	rl, err = rlf.GetOrCreate("testchannelid")
   529  	require.NoError(t, err)
   530  	err = rl.Append(configBlock)
   531  	require.NoError(t, err)
   532  
   533  	lastConf = extractSystemChannel(rlf, cryptoProvider)
   534  	require.NotNil(t, lastConf, "get system channel genesis block")
   535  	require.Equal(t, uint64(0), lastConf.Header.Number)
   536  
   537  	// Make and append the next config block
   538  	prevHash := protoutil.BlockHeaderHash(configBlock.Header)
   539  	configBlock.Header.Number = 1
   540  	configBlock.Header.PreviousHash = prevHash
   541  	configBlock.Metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.Metadata{
   542  		Value: protoutil.MarshalOrPanic(&common.OrdererBlockMetadata{
   543  			LastConfig: &common.LastConfig{Index: rl.Height()},
   544  		}),
   545  	})
   546  	configBlock.Metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{
   547  		Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: rl.Height()}),
   548  	})
   549  	err = rl.Append(configBlock)
   550  	require.NoError(t, err)
   551  
   552  	lastConf = extractSystemChannel(rlf, cryptoProvider)
   553  	require.NotNil(t, lastConf, "get system channel last config block")
   554  	require.Equal(t, uint64(1), lastConf.Header.Number)
   555  }
   556  
   557  func TestSelectClusterBootBlock(t *testing.T) {
   558  	bootstrapBlock := &common.Block{Header: &common.BlockHeader{Number: 100}}
   559  	lastConfBlock := &common.Block{Header: &common.BlockHeader{Number: 100}}
   560  
   561  	clusterBoot := selectClusterBootBlock(bootstrapBlock, nil)
   562  	require.NotNil(t, clusterBoot)
   563  	require.Equal(t, uint64(100), clusterBoot.Header.Number)
   564  	require.True(t, bootstrapBlock == clusterBoot)
   565  
   566  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   567  	require.NotNil(t, clusterBoot)
   568  	require.Equal(t, uint64(100), clusterBoot.Header.Number)
   569  	require.True(t, bootstrapBlock == clusterBoot)
   570  
   571  	lastConfBlock.Header.Number = 200
   572  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   573  	require.NotNil(t, clusterBoot)
   574  	require.Equal(t, uint64(200), clusterBoot.Header.Number)
   575  	require.True(t, lastConfBlock == clusterBoot)
   576  
   577  	bootstrapBlock.Header.Number = 300
   578  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   579  	require.NotNil(t, clusterBoot)
   580  	require.Equal(t, uint64(300), clusterBoot.Header.Number)
   581  	require.True(t, bootstrapBlock == clusterBoot)
   582  }
   583  
   584  func TestLoadLocalMSP(t *testing.T) {
   585  	t.Run("Happy", func(t *testing.T) {
   586  		localMSPDir := configtest.GetDevMspDir()
   587  		localMSP := loadLocalMSP(
   588  			&localconfig.TopLevel{
   589  				General: localconfig.General{
   590  					LocalMSPDir: localMSPDir,
   591  					LocalMSPID:  "SampleOrg",
   592  					BCCSP: &factory.FactoryOpts{
   593  						Default: "SW",
   594  						SW: &factory.SwOpts{
   595  							Hash:     "SHA2",
   596  							Security: 256,
   597  						},
   598  					},
   599  				},
   600  			},
   601  		)
   602  		require.NotNil(t, localMSP)
   603  		id, err := localMSP.GetIdentifier()
   604  		require.NoError(t, err)
   605  		require.Equal(t, id, "SampleOrg")
   606  	})
   607  
   608  	t.Run("Error", func(t *testing.T) {
   609  		oldLogger := logger
   610  		defer func() { logger = oldLogger }()
   611  		logger, _ = floggingtest.NewTestLogger(t)
   612  
   613  		require.Panics(t, func() {
   614  			loadLocalMSP(
   615  				&localconfig.TopLevel{
   616  					General: localconfig.General{
   617  						LocalMSPDir: "",
   618  						LocalMSPID:  "",
   619  					},
   620  				},
   621  			)
   622  		})
   623  	})
   624  }
   625  
   626  func TestInitializeMultichannelRegistrar(t *testing.T) {
   627  	cleanup := configtest.SetDevFabricConfigPath(t)
   628  	defer cleanup()
   629  	genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid")
   630  	defer os.Remove(genesisFile)
   631  
   632  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   633  	require.NoError(t, err)
   634  
   635  	signer := &server_mocks.SignerSerializer{}
   636  
   637  	t.Run("registrar with a system channel", func(t *testing.T) {
   638  		conf, ledgerDir := genesisConfig(t, genesisFile)
   639  		defer os.RemoveAll(ledgerDir)
   640  		lf, err := createLedgerFactory(conf, &disabled.Provider{})
   641  		require.NoError(t, err)
   642  		bootBlock := file.New(genesisFile).GenesisBlock()
   643  		initializeBootstrapChannel(bootBlock, lf)
   644  		registrar := initializeMultichannelRegistrar(
   645  			bootBlock,
   646  			onboarding.NewReplicationInitiator(lf, bootBlock, conf, comm.SecureOptions{}, signer, cryptoProvider),
   647  			&cluster.PredicateDialer{},
   648  			comm.ServerConfig{},
   649  			nil,
   650  			conf,
   651  			signer,
   652  			&disabled.Provider{},
   653  			&server_mocks.HealthChecker{},
   654  			lf,
   655  			cryptoProvider,
   656  		)
   657  		require.NotNil(t, registrar)
   658  		require.Equal(t, "testchannelid", registrar.SystemChannelID())
   659  	})
   660  
   661  	t.Run("registrar without a system channel", func(t *testing.T) {
   662  		conf, ledgerDir := genesisConfig(t, genesisFile)
   663  		defer os.RemoveAll(ledgerDir)
   664  		conf.General.BootstrapMethod = "none"
   665  		conf.General.GenesisFile = ""
   666  		srv, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{})
   667  		require.NoError(t, err)
   668  		lf, err := createLedgerFactory(conf, &disabled.Provider{})
   669  		require.NoError(t, err)
   670  		registrar := initializeMultichannelRegistrar(
   671  			nil,
   672  			nil,
   673  			&cluster.PredicateDialer{},
   674  			comm.ServerConfig{},
   675  			srv,
   676  			conf,
   677  			signer,
   678  			&disabled.Provider{},
   679  			&server_mocks.HealthChecker{},
   680  			lf,
   681  			cryptoProvider,
   682  		)
   683  		require.NotNil(t, registrar)
   684  		require.Empty(t, registrar.SystemChannelID())
   685  	})
   686  }
   687  
   688  func TestInitializeGrpcServer(t *testing.T) {
   689  	// get a free random port
   690  	listenAddr := func() string {
   691  		l, _ := net.Listen("tcp", "localhost:0")
   692  		l.Close()
   693  		return l.Addr().String()
   694  	}()
   695  	host := strings.Split(listenAddr, ":")[0]
   696  	port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16)
   697  	conf := &localconfig.TopLevel{
   698  		General: localconfig.General{
   699  			ListenAddress: host,
   700  			ListenPort:    uint16(port),
   701  			TLS: localconfig.TLS{
   702  				Enabled:            false,
   703  				ClientAuthRequired: false,
   704  			},
   705  		},
   706  	}
   707  	require.NotPanics(t, func() {
   708  		grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   709  		grpcServer.Listener().Close()
   710  	})
   711  }
   712  
   713  // generateCryptoMaterials uses cryptogen to generate the necessary
   714  // MSP files and TLS certificates
   715  func generateCryptoMaterials(t *testing.T, cryptogen string) string {
   716  	gt := NewGomegaWithT(t)
   717  	cryptoPath := filepath.Join(tempDir, "crypto")
   718  
   719  	cmd := exec.Command(
   720  		cryptogen,
   721  		"generate",
   722  		"--config", filepath.Join(tempDir, "examplecom-config.yaml"),
   723  		"--output", cryptoPath,
   724  	)
   725  	cryptogenProcess, err := gexec.Start(cmd, nil, nil)
   726  	gt.Expect(err).NotTo(HaveOccurred())
   727  	gt.Eventually(cryptogenProcess, time.Minute).Should(gexec.Exit(0))
   728  
   729  	return cryptoPath
   730  }
   731  
   732  func TestUpdateTrustedRoots(t *testing.T) {
   733  	cleanup := configtest.SetDevFabricConfigPath(t)
   734  	defer cleanup()
   735  
   736  	genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid")
   737  	defer os.Remove(genesisFile)
   738  
   739  	cryptoPath := generateCryptoMaterials(t, cryptogen)
   740  	defer os.RemoveAll(cryptoPath)
   741  
   742  	// get a free random port
   743  	listenAddr := func() string {
   744  		l, _ := net.Listen("tcp", "localhost:0")
   745  		l.Close()
   746  		return l.Addr().String()
   747  	}()
   748  	port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16)
   749  	tempDir, err := ioutil.TempDir("", "ledger-dir")
   750  	require.NoError(t, err)
   751  	conf := &localconfig.TopLevel{
   752  		General: localconfig.General{
   753  			BootstrapMethod: "file",
   754  			BootstrapFile:   genesisFile,
   755  			ListenAddress:   "localhost",
   756  			ListenPort:      uint16(port),
   757  			TLS: localconfig.TLS{
   758  				Enabled:            false,
   759  				ClientAuthRequired: false,
   760  			},
   761  		},
   762  		FileLedger: localconfig.FileLedger{
   763  			Location: tempDir,
   764  		},
   765  	}
   766  	grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   767  	caMgr := &caManager{
   768  		appRootCAsByChain:     make(map[string][][]byte),
   769  		ordererRootCAsByChain: make(map[string][][]byte),
   770  	}
   771  	callback := func(bundle *channelconfig.Bundle) {
   772  		if grpcServer.MutualTLSRequired() {
   773  			t.Log("callback called")
   774  			caMgr.updateTrustedRoots(bundle, grpcServer)
   775  		}
   776  	}
   777  	lf, err := createLedgerFactory(conf, &disabled.Provider{})
   778  	require.NoError(t, err)
   779  	bootBlock := file.New(genesisFile).GenesisBlock()
   780  	initializeBootstrapChannel(bootBlock, lf)
   781  	signer := &server_mocks.SignerSerializer{}
   782  
   783  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   784  	require.NoError(t, err)
   785  
   786  	genConfig, ledgerDir := genesisConfig(t, genesisFile)
   787  	defer os.RemoveAll(ledgerDir)
   788  
   789  	initializeMultichannelRegistrar(
   790  		bootBlock,
   791  		onboarding.NewReplicationInitiator(lf, bootBlock, conf, comm.SecureOptions{}, signer, cryptoProvider),
   792  		&cluster.PredicateDialer{},
   793  		comm.ServerConfig{},
   794  		nil,
   795  		genConfig,
   796  		signer,
   797  		&disabled.Provider{},
   798  		&server_mocks.HealthChecker{},
   799  		lf,
   800  		cryptoProvider,
   801  		callback,
   802  	)
   803  	t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"]))
   804  	t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"]))
   805  	// mutual TLS not required so no updates should have occurred
   806  	require.Equal(t, 0, len(caMgr.appRootCAsByChain["testchannelid"]))
   807  	require.Equal(t, 0, len(caMgr.ordererRootCAsByChain["testchannelid"]))
   808  	grpcServer.Listener().Close()
   809  
   810  	conf = &localconfig.TopLevel{
   811  		General: localconfig.General{
   812  			ListenAddress: "localhost",
   813  			ListenPort:    uint16(port),
   814  			TLS: localconfig.TLS{
   815  				Enabled:            true,
   816  				ClientAuthRequired: true,
   817  				PrivateKey:         filepath.Join(cryptoPath, "ordererOrganizations", "example.com", "orderers", "127.0.0.1.example.com", "tls", "server.key"),
   818  				Certificate:        filepath.Join(cryptoPath, "ordererOrganizations", "example.com", "orderers", "127.0.0.1.example.com", "tls", "server.crt"),
   819  			},
   820  		},
   821  	}
   822  	grpcServer = initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   823  	caMgr = &caManager{
   824  		appRootCAsByChain:     make(map[string][][]byte),
   825  		ordererRootCAsByChain: make(map[string][][]byte),
   826  	}
   827  
   828  	clusterConf, _ := initializeClusterClientConfig(conf)
   829  	predDialer := &cluster.PredicateDialer{
   830  		Config: clusterConf,
   831  	}
   832  
   833  	callback = func(bundle *channelconfig.Bundle) {
   834  		if grpcServer.MutualTLSRequired() {
   835  			t.Log("callback called")
   836  			caMgr.updateTrustedRoots(bundle, grpcServer)
   837  			caMgr.updateClusterDialer(predDialer, clusterConf.SecOpts.ServerRootCAs)
   838  		}
   839  	}
   840  	genConfig2, ledgerDir2 := genesisConfig(t, genesisFile)
   841  	defer os.RemoveAll(ledgerDir2)
   842  
   843  	initializeMultichannelRegistrar(
   844  		bootBlock,
   845  		onboarding.NewReplicationInitiator(lf, bootBlock, conf, comm.SecureOptions{}, signer, cryptoProvider),
   846  		predDialer,
   847  		comm.ServerConfig{},
   848  		nil,
   849  		genConfig2,
   850  		signer,
   851  		&disabled.Provider{},
   852  		&server_mocks.HealthChecker{},
   853  		lf,
   854  		cryptoProvider,
   855  		callback,
   856  	)
   857  	t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"]))
   858  	t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"]))
   859  	// mutual TLS is required so updates should have occurred
   860  	// we expect an intermediate and root CA for apps and orderers
   861  	require.Equal(t, 2, len(caMgr.appRootCAsByChain["testchannelid"]))
   862  	require.Equal(t, 2, len(caMgr.ordererRootCAsByChain["testchannelid"]))
   863  	require.Len(t, predDialer.Config.SecOpts.ServerRootCAs, 2)
   864  	grpcServer.Listener().Close()
   865  }
   866  
   867  func TestRootServerCertAggregation(t *testing.T) {
   868  	caMgr := &caManager{
   869  		appRootCAsByChain:     make(map[string][][]byte),
   870  		ordererRootCAsByChain: make(map[string][][]byte),
   871  	}
   872  
   873  	predDialer := &cluster.PredicateDialer{
   874  		Config: comm.ClientConfig{},
   875  	}
   876  
   877  	ca1, err := tlsgen.NewCA()
   878  	require.NoError(t, err)
   879  
   880  	ca2, err := tlsgen.NewCA()
   881  	require.NoError(t, err)
   882  
   883  	caMgr.ordererRootCAsByChain["foo"] = [][]byte{ca1.CertBytes()}
   884  	caMgr.ordererRootCAsByChain["bar"] = [][]byte{ca1.CertBytes()}
   885  
   886  	caMgr.updateClusterDialer(predDialer, [][]byte{ca2.CertBytes(), ca2.CertBytes(), ca2.CertBytes()})
   887  
   888  	require.Len(t, predDialer.Config.SecOpts.ServerRootCAs, 2)
   889  	require.Contains(t, predDialer.Config.SecOpts.ServerRootCAs, ca1.CertBytes())
   890  	require.Contains(t, predDialer.Config.SecOpts.ServerRootCAs, ca2.CertBytes())
   891  }
   892  
   893  func TestConfigureClusterListener(t *testing.T) {
   894  	logEntries := make(chan string, 100)
   895  
   896  	allocatePort := func() uint16 {
   897  		l, err := net.Listen("tcp", "127.0.0.1:0")
   898  		require.NoError(t, err)
   899  		_, portStr, err := net.SplitHostPort(l.Addr().String())
   900  		require.NoError(t, err)
   901  		port, err := strconv.ParseInt(portStr, 10, 64)
   902  		require.NoError(t, err)
   903  		require.NoError(t, l.Close())
   904  		t.Log("picked unused port", port)
   905  		return uint16(port)
   906  	}
   907  
   908  	unUsedPort := allocatePort()
   909  
   910  	backupLogger := logger
   911  	logger = logger.WithOptions(zap.Hooks(func(entry zapcore.Entry) error {
   912  		logEntries <- entry.Message
   913  		return nil
   914  	}))
   915  
   916  	defer func() {
   917  		logger = backupLogger
   918  	}()
   919  
   920  	ca, err := tlsgen.NewCA()
   921  	require.NoError(t, err)
   922  	serverKeyPair, err := ca.NewServerCertKeyPair("127.0.0.1")
   923  	require.NoError(t, err)
   924  
   925  	loadPEM := func(fileName string) ([]byte, error) {
   926  		switch fileName {
   927  		case "cert":
   928  			return serverKeyPair.Cert, nil
   929  		case "key":
   930  			return serverKeyPair.Key, nil
   931  		case "ca":
   932  			return ca.CertBytes(), nil
   933  		default:
   934  			return nil, errors.New("I/O error")
   935  		}
   936  	}
   937  
   938  	for _, testCase := range []struct {
   939  		name               string
   940  		conf               *localconfig.TopLevel
   941  		generalConf        comm.ServerConfig
   942  		generalSrv         *comm.GRPCServer
   943  		shouldBeEqual      bool
   944  		expectedPanic      string
   945  		expectedLogEntries []string
   946  	}{
   947  		{
   948  			name:        "invalid certificate",
   949  			generalConf: comm.ServerConfig{},
   950  			conf: &localconfig.TopLevel{
   951  				General: localconfig.General{
   952  					Cluster: localconfig.Cluster{
   953  						ListenAddress:     "127.0.0.1",
   954  						ListenPort:        5000,
   955  						ServerPrivateKey:  "key",
   956  						ServerCertificate: "bad",
   957  						RootCAs:           []string{"ca"},
   958  					},
   959  				},
   960  			},
   961  			expectedPanic:      "Failed to load cluster server certificate from 'bad' (I/O error)",
   962  			generalSrv:         &comm.GRPCServer{},
   963  			expectedLogEntries: []string{"Failed to load cluster server certificate from 'bad' (I/O error)"},
   964  		},
   965  		{
   966  			name:        "invalid key",
   967  			generalConf: comm.ServerConfig{},
   968  			conf: &localconfig.TopLevel{
   969  				General: localconfig.General{
   970  					Cluster: localconfig.Cluster{
   971  						ListenAddress:     "127.0.0.1",
   972  						ListenPort:        5000,
   973  						ServerPrivateKey:  "bad",
   974  						ServerCertificate: "cert",
   975  						RootCAs:           []string{"ca"},
   976  					},
   977  				},
   978  			},
   979  			expectedPanic:      "Failed to load cluster server key from 'bad' (I/O error)",
   980  			generalSrv:         &comm.GRPCServer{},
   981  			expectedLogEntries: []string{"Failed to load cluster server key from 'bad' (I/O error)"},
   982  		},
   983  		{
   984  			name:        "invalid ca cert",
   985  			generalConf: comm.ServerConfig{},
   986  			conf: &localconfig.TopLevel{
   987  				General: localconfig.General{
   988  					Cluster: localconfig.Cluster{
   989  						ListenAddress:     "127.0.0.1",
   990  						ListenPort:        5000,
   991  						ServerPrivateKey:  "key",
   992  						ServerCertificate: "cert",
   993  						RootCAs:           []string{"bad"},
   994  					},
   995  				},
   996  			},
   997  			expectedPanic:      "Failed to load CA cert file 'bad' (I/O error)",
   998  			generalSrv:         &comm.GRPCServer{},
   999  			expectedLogEntries: []string{"Failed to load CA cert file 'bad' (I/O error)"},
  1000  		},
  1001  		{
  1002  			name:        "bad listen address",
  1003  			generalConf: comm.ServerConfig{},
  1004  			conf: &localconfig.TopLevel{
  1005  				General: localconfig.General{
  1006  					Cluster: localconfig.Cluster{
  1007  						ListenAddress:     "99.99.99.99",
  1008  						ListenPort:        unUsedPort,
  1009  						ServerPrivateKey:  "key",
  1010  						ServerCertificate: "cert",
  1011  						RootCAs:           []string{"ca"},
  1012  					},
  1013  				},
  1014  			},
  1015  			expectedPanic: fmt.Sprintf("Failed creating gRPC server on 99.99.99.99:%d due "+
  1016  				"to listen tcp 99.99.99.99:%d:", unUsedPort, unUsedPort),
  1017  			generalSrv: &comm.GRPCServer{},
  1018  		},
  1019  		{
  1020  			name:        "green path",
  1021  			generalConf: comm.ServerConfig{},
  1022  			conf: &localconfig.TopLevel{
  1023  				General: localconfig.General{
  1024  					Cluster: localconfig.Cluster{
  1025  						ListenAddress:     "127.0.0.1",
  1026  						ListenPort:        5000,
  1027  						ServerPrivateKey:  "key",
  1028  						ServerCertificate: "cert",
  1029  						RootCAs:           []string{"ca"},
  1030  					},
  1031  				},
  1032  			},
  1033  			generalSrv: &comm.GRPCServer{},
  1034  		},
  1035  	} {
  1036  		t.Run(testCase.name, func(t *testing.T) {
  1037  			if testCase.shouldBeEqual {
  1038  				conf, srv := configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
  1039  				require.Equal(t, conf, testCase.generalConf)
  1040  				require.Equal(t, srv, testCase.generalSrv)
  1041  			}
  1042  
  1043  			if testCase.expectedPanic != "" {
  1044  				f := func() {
  1045  					configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
  1046  				}
  1047  				require.Contains(t, panicMsg(f), testCase.expectedPanic)
  1048  			} else {
  1049  				configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
  1050  			}
  1051  			// Ensure logged messages that are expected were all logged
  1052  			var loggedMessages []string
  1053  			for len(logEntries) > 0 {
  1054  				logEntry := <-logEntries
  1055  				loggedMessages = append(loggedMessages, logEntry)
  1056  			}
  1057  			require.Subset(t, loggedMessages, testCase.expectedLogEntries)
  1058  		})
  1059  	}
  1060  }
  1061  
  1062  func TestReuseListener(t *testing.T) {
  1063  	t.Run("good to reuse", func(t *testing.T) {
  1064  		top := &localconfig.TopLevel{General: localconfig.General{TLS: localconfig.TLS{Enabled: true}}}
  1065  		require.True(t, reuseListener(top))
  1066  	})
  1067  
  1068  	t.Run("reuse tls disabled", func(t *testing.T) {
  1069  		top := &localconfig.TopLevel{}
  1070  		require.PanicsWithValue(
  1071  			t,
  1072  			"TLS is required for running ordering nodes of cluster type.",
  1073  			func() { reuseListener(top) },
  1074  		)
  1075  	})
  1076  
  1077  	t.Run("good not to reuse", func(t *testing.T) {
  1078  		top := &localconfig.TopLevel{
  1079  			General: localconfig.General{
  1080  				Cluster: localconfig.Cluster{
  1081  					ListenAddress:     "127.0.0.1",
  1082  					ListenPort:        5000,
  1083  					ServerPrivateKey:  "key",
  1084  					ServerCertificate: "bad",
  1085  				},
  1086  			},
  1087  		}
  1088  		require.False(t, reuseListener(top))
  1089  	})
  1090  
  1091  	t.Run("partial config", func(t *testing.T) {
  1092  		top := &localconfig.TopLevel{
  1093  			General: localconfig.General{
  1094  				Cluster: localconfig.Cluster{
  1095  					ListenAddress:     "127.0.0.1",
  1096  					ListenPort:        5000,
  1097  					ServerCertificate: "bad",
  1098  				},
  1099  			},
  1100  		}
  1101  		require.PanicsWithValue(
  1102  			t,
  1103  			"Options: General.Cluster.ListenPort, General.Cluster.ListenAddress,"+
  1104  				" General.Cluster.ServerCertificate, General.Cluster.ServerPrivateKey, should be defined altogether.",
  1105  			func() { reuseListener(top) },
  1106  		)
  1107  	})
  1108  }
  1109  
  1110  func TestInitializeEtcdraftConsenter(t *testing.T) {
  1111  	consenters := make(map[string]consensus.Consenter)
  1112  
  1113  	tmpdir, err := ioutil.TempDir("", "main_test-")
  1114  	require.NoError(t, err)
  1115  	defer os.RemoveAll(tmpdir)
  1116  	rlf, err := fileledger.New(tmpdir, &disabled.Provider{})
  1117  	require.NoError(t, err)
  1118  
  1119  	conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
  1120  	genesisBlock := encoder.New(conf).GenesisBlock()
  1121  
  1122  	ca, _ := tlsgen.NewCA()
  1123  	crt, _ := ca.NewServerCertKeyPair("127.0.0.1")
  1124  
  1125  	srv, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{})
  1126  	require.NoError(t, err)
  1127  
  1128  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
  1129  	require.NoError(t, err)
  1130  
  1131  	initializeEtcdraftConsenter(
  1132  		consenters,
  1133  		&localconfig.TopLevel{},
  1134  		rlf,
  1135  		&cluster.PredicateDialer{},
  1136  		genesisBlock,
  1137  		onboarding.NewReplicationInitiator(rlf, genesisBlock, nil, comm.SecureOptions{}, nil, cryptoProvider),
  1138  		comm.ServerConfig{
  1139  			SecOpts: comm.SecureOptions{
  1140  				Certificate: crt.Cert,
  1141  				Key:         crt.Key,
  1142  				UseTLS:      true,
  1143  			},
  1144  		},
  1145  		srv,
  1146  		&multichannel.Registrar{},
  1147  		&disabled.Provider{},
  1148  		cryptoProvider,
  1149  	)
  1150  	require.NotNil(t, consenters["etcdraft"])
  1151  }
  1152  
  1153  func genesisConfig(t *testing.T, genesisFile string) (*localconfig.TopLevel, string) {
  1154  	t.Helper()
  1155  	localMSPDir := configtest.GetDevMspDir()
  1156  	ledgerDir, err := ioutil.TempDir("", "genesis-config")
  1157  	require.NoError(t, err)
  1158  
  1159  	return &localconfig.TopLevel{
  1160  		General: localconfig.General{
  1161  			BootstrapMethod: "file",
  1162  			BootstrapFile:   genesisFile,
  1163  			LocalMSPDir:     localMSPDir,
  1164  			LocalMSPID:      "SampleOrg",
  1165  			BCCSP: &factory.FactoryOpts{
  1166  				Default: "SW",
  1167  				SW: &factory.SwOpts{
  1168  					Hash:     "SHA2",
  1169  					Security: 256,
  1170  				},
  1171  			},
  1172  		},
  1173  		FileLedger: localconfig.FileLedger{
  1174  			Location: ledgerDir,
  1175  		},
  1176  	}, ledgerDir
  1177  }
  1178  
  1179  func panicMsg(f func()) string {
  1180  	var message interface{}
  1181  	func() {
  1182  		defer func() {
  1183  			message = recover()
  1184  		}()
  1185  
  1186  		f()
  1187  	}()
  1188  
  1189  	return message.(string)
  1190  }
  1191  
  1192  func produceGenesisFile(t *testing.T, profile, channelID string) string {
  1193  	conf := genesisconfig.Load(profile, configtest.GetDevConfigDir())
  1194  	f, err := ioutil.TempFile("", fmt.Sprintf("%s-genesis_block-", t.Name()))
  1195  	require.NoError(t, err)
  1196  	_, err = f.Write(protoutil.MarshalOrPanic(encoder.New(conf).GenesisBlockForChannel(channelID)))
  1197  	require.NoError(t, err)
  1198  	err = f.Close()
  1199  	require.NoError(t, err)
  1200  	return f.Name()
  1201  }