github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/orderer/common/server/main_test.go (about)

     1  // Copyright IBM Corp. 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  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/golang/protobuf/proto"
    19  	"github.com/hyperledger/fabric-protos-go/common"
    20  	"github.com/hyperledger/fabric/bccsp/factory"
    21  	"github.com/hyperledger/fabric/bccsp/sw"
    22  	"github.com/hyperledger/fabric/common/channelconfig"
    23  	"github.com/hyperledger/fabric/common/crypto/tlsgen"
    24  	deliver_mocks "github.com/hyperledger/fabric/common/deliver/mock"
    25  	"github.com/hyperledger/fabric/common/flogging"
    26  	"github.com/hyperledger/fabric/common/flogging/floggingtest"
    27  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    28  	"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger"
    29  	ledger_mocks "github.com/hyperledger/fabric/common/ledger/blockledger/mocks"
    30  	"github.com/hyperledger/fabric/common/metrics/disabled"
    31  	"github.com/hyperledger/fabric/common/metrics/prometheus"
    32  	"github.com/hyperledger/fabric/core/comm"
    33  	"github.com/hyperledger/fabric/core/config/configtest"
    34  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    35  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    36  	"github.com/hyperledger/fabric/internal/pkg/identity"
    37  	"github.com/hyperledger/fabric/orderer/common/bootstrap/file"
    38  	"github.com/hyperledger/fabric/orderer/common/cluster"
    39  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    40  	"github.com/hyperledger/fabric/orderer/common/multichannel"
    41  	server_mocks "github.com/hyperledger/fabric/orderer/common/server/mocks"
    42  	"github.com/hyperledger/fabric/orderer/consensus"
    43  	"github.com/hyperledger/fabric/protoutil"
    44  	"github.com/pkg/errors"
    45  	"github.com/stretchr/testify/assert"
    46  	"github.com/stretchr/testify/mock"
    47  	"github.com/stretchr/testify/require"
    48  	"go.uber.org/zap"
    49  	"go.uber.org/zap/zapcore"
    50  )
    51  
    52  //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    53  
    54  type signerSerializer interface {
    55  	identity.SignerSerializer
    56  }
    57  
    58  func TestInitializeLogging(t *testing.T) {
    59  	origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC")
    60  	os.Setenv("FABRIC_LOGGING_SPEC", "foo=debug")
    61  	initializeLogging()
    62  	assert.Equal(t, "debug", flogging.LoggerLevel("foo"))
    63  	os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue)
    64  }
    65  
    66  func TestInitializeProfilingService(t *testing.T) {
    67  	origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC")
    68  	defer os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue)
    69  	os.Setenv("FABRIC_LOGGING_SPEC", "debug")
    70  	// get a free random port
    71  	listenAddr := func() string {
    72  		l, _ := net.Listen("tcp", "localhost:0")
    73  		l.Close()
    74  		return l.Addr().String()
    75  	}()
    76  	go initializeProfilingService(
    77  		&localconfig.TopLevel{
    78  			General: localconfig.General{
    79  				Profile: localconfig.Profile{
    80  					Enabled: true,
    81  					Address: listenAddr,
    82  				}},
    83  			Kafka: localconfig.Kafka{Verbose: true},
    84  		},
    85  	)
    86  	time.Sleep(500 * time.Millisecond)
    87  	if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil {
    88  		t.Logf("Expected pprof to be up (will retry again in 3 seconds): %s", err)
    89  		time.Sleep(3 * time.Second)
    90  		if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil {
    91  			t.Fatalf("Expected pprof to be up: %s", err)
    92  		}
    93  	}
    94  }
    95  
    96  func TestInitializeServerConfig(t *testing.T) {
    97  	conf := &localconfig.TopLevel{
    98  		General: localconfig.General{
    99  			ConnectionTimeout: 7 * time.Second,
   100  			TLS: localconfig.TLS{
   101  				Enabled:            true,
   102  				ClientAuthRequired: true,
   103  				Certificate:        "main.go",
   104  				PrivateKey:         "main.go",
   105  				RootCAs:            []string{"main.go"},
   106  				ClientRootCAs:      []string{"main.go"},
   107  			},
   108  		},
   109  	}
   110  	sc := initializeServerConfig(conf, nil)
   111  	expectedContent, _ := ioutil.ReadFile("main.go")
   112  	assert.Equal(t, expectedContent, sc.SecOpts.Certificate)
   113  	assert.Equal(t, expectedContent, sc.SecOpts.Key)
   114  	assert.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ServerRootCAs)
   115  	assert.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ClientRootCAs)
   116  
   117  	sc = initializeServerConfig(conf, nil)
   118  	defaultOpts := comm.DefaultKeepaliveOptions
   119  	assert.Equal(t, defaultOpts.ServerMinInterval, sc.KaOpts.ServerMinInterval)
   120  	assert.Equal(t, time.Duration(0), sc.KaOpts.ServerInterval)
   121  	assert.Equal(t, time.Duration(0), sc.KaOpts.ServerTimeout)
   122  	assert.Equal(t, 7*time.Second, sc.ConnectionTimeout)
   123  	testDuration := 10 * time.Second
   124  	conf.General.Keepalive = localconfig.Keepalive{
   125  		ServerMinInterval: testDuration,
   126  		ServerInterval:    testDuration,
   127  		ServerTimeout:     testDuration,
   128  	}
   129  	sc = initializeServerConfig(conf, nil)
   130  	assert.Equal(t, testDuration, sc.KaOpts.ServerMinInterval)
   131  	assert.Equal(t, testDuration, sc.KaOpts.ServerInterval)
   132  	assert.Equal(t, testDuration, sc.KaOpts.ServerTimeout)
   133  
   134  	sc = initializeServerConfig(conf, nil)
   135  	assert.NotNil(t, sc.Logger)
   136  	assert.Equal(t, comm.NewServerStatsHandler(&disabled.Provider{}), sc.ServerStatsHandler)
   137  	assert.Len(t, sc.UnaryInterceptors, 2)
   138  	assert.Len(t, sc.StreamInterceptors, 2)
   139  
   140  	sc = initializeServerConfig(conf, &prometheus.Provider{})
   141  	assert.NotNil(t, sc.ServerStatsHandler)
   142  
   143  	goodFile := "main.go"
   144  	badFile := "does_not_exist"
   145  
   146  	oldLogger := logger
   147  	defer func() { logger = oldLogger }()
   148  	logger, _ = floggingtest.NewTestLogger(t)
   149  
   150  	testCases := []struct {
   151  		name           string
   152  		certificate    string
   153  		privateKey     string
   154  		rootCA         string
   155  		clientRootCert string
   156  		clusterCert    string
   157  		clusterKey     string
   158  		clusterCA      string
   159  	}{
   160  		{"BadCertificate", badFile, goodFile, goodFile, goodFile, "", "", ""},
   161  		{"BadPrivateKey", goodFile, badFile, goodFile, goodFile, "", "", ""},
   162  		{"BadRootCA", goodFile, goodFile, badFile, goodFile, "", "", ""},
   163  		{"BadClientRootCertificate", goodFile, goodFile, goodFile, badFile, "", "", ""},
   164  		{"ClusterBadCertificate", goodFile, goodFile, goodFile, goodFile, badFile, goodFile, goodFile},
   165  		{"ClusterBadPrivateKey", goodFile, goodFile, goodFile, goodFile, goodFile, badFile, goodFile},
   166  		{"ClusterBadRootCA", goodFile, goodFile, goodFile, goodFile, goodFile, goodFile, badFile},
   167  	}
   168  	for _, tc := range testCases {
   169  		t.Run(tc.name, func(t *testing.T) {
   170  			conf := &localconfig.TopLevel{
   171  				General: localconfig.General{
   172  					TLS: localconfig.TLS{
   173  						Enabled:            true,
   174  						ClientAuthRequired: true,
   175  						Certificate:        tc.certificate,
   176  						PrivateKey:         tc.privateKey,
   177  						RootCAs:            []string{tc.rootCA},
   178  						ClientRootCAs:      []string{tc.clientRootCert},
   179  					},
   180  					Cluster: localconfig.Cluster{
   181  						ClientCertificate: tc.clusterCert,
   182  						ClientPrivateKey:  tc.clusterKey,
   183  						RootCAs:           []string{tc.clusterCA},
   184  					},
   185  				},
   186  			}
   187  			assert.Panics(t, func() {
   188  				if tc.clusterCert == "" {
   189  					initializeServerConfig(conf, nil)
   190  				} else {
   191  					initializeClusterClientConfig(conf)
   192  				}
   193  			},
   194  			)
   195  		})
   196  	}
   197  }
   198  
   199  func TestInitializeBootstrapChannel(t *testing.T) {
   200  	cleanup := configtest.SetDevFabricConfigPath(t)
   201  	defer cleanup()
   202  
   203  	genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid")
   204  	defer os.Remove(genesisFile)
   205  
   206  	fileLedgerLocation, _ := ioutil.TempDir("", "main_test-")
   207  	ledgerFactory, _, err := createLedgerFactory(
   208  		&localconfig.TopLevel{
   209  			FileLedger: localconfig.FileLedger{
   210  				Location: fileLedgerLocation,
   211  			},
   212  		},
   213  		&disabled.Provider{},
   214  	)
   215  	assert.NoError(t, err)
   216  	bootstrapConfig := &localconfig.TopLevel{
   217  		General: localconfig.General{
   218  			BootstrapMethod: "file",
   219  			BootstrapFile:   genesisFile,
   220  		},
   221  	}
   222  
   223  	bootstrapBlock := extractBootstrapBlock(bootstrapConfig)
   224  	initializeBootstrapChannel(bootstrapBlock, ledgerFactory)
   225  
   226  	ledger, err := ledgerFactory.GetOrCreate("testchannelid")
   227  	assert.NoError(t, err)
   228  	assert.Equal(t, uint64(1), ledger.Height())
   229  }
   230  
   231  func TestExtractBootstrapBlock(t *testing.T) {
   232  	cleanup := configtest.SetDevFabricConfigPath(t)
   233  	defer cleanup()
   234  
   235  	genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid")
   236  	defer os.Remove(genesisFile)
   237  
   238  	tests := []struct {
   239  		config *localconfig.TopLevel
   240  		block  *common.Block
   241  	}{
   242  		{
   243  			config: &localconfig.TopLevel{
   244  				General: localconfig.General{BootstrapMethod: "file", BootstrapFile: genesisFile},
   245  			},
   246  			block: file.New(genesisFile).GenesisBlock(),
   247  		},
   248  		{
   249  			config: &localconfig.TopLevel{
   250  				General: localconfig.General{BootstrapMethod: "none"},
   251  			},
   252  			block: nil,
   253  		},
   254  	}
   255  	for _, tt := range tests {
   256  		b := extractBootstrapBlock(tt.config)
   257  		assert.Truef(t, proto.Equal(tt.block, b), "wanted %v, got %v", tt.block, b)
   258  	}
   259  }
   260  
   261  func TestExtractSysChanLastConfig(t *testing.T) {
   262  	tmpdir, err := ioutil.TempDir("", "main_test-")
   263  	require.NoError(t, err)
   264  	defer os.RemoveAll(tmpdir)
   265  
   266  	rlf, err := fileledger.New(tmpdir, &disabled.Provider{})
   267  	require.NoError(t, err)
   268  
   269  	conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   270  	genesisBlock := encoder.New(conf).GenesisBlock()
   271  
   272  	lastConf := extractSysChanLastConfig(rlf, genesisBlock)
   273  	assert.Nil(t, lastConf)
   274  
   275  	rl, err := rlf.GetOrCreate("testchannelid")
   276  	require.NoError(t, err)
   277  
   278  	err = rl.Append(genesisBlock)
   279  	require.NoError(t, err)
   280  
   281  	lastConf = extractSysChanLastConfig(rlf, genesisBlock)
   282  	assert.NotNil(t, lastConf)
   283  	assert.Equal(t, uint64(0), lastConf.Header.Number)
   284  
   285  	assert.Panics(t, func() {
   286  		_ = extractSysChanLastConfig(rlf, nil)
   287  	})
   288  
   289  	configTx, err := protoutil.CreateSignedEnvelope(common.HeaderType_CONFIG, "testchannelid", nil, &common.ConfigEnvelope{}, 0, 0)
   290  	require.NoError(t, err)
   291  
   292  	nextBlock := blockledger.CreateNextBlock(rl, []*common.Envelope{configTx})
   293  	nextBlock.Metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{
   294  		Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: rl.Height()}),
   295  	})
   296  	err = rl.Append(nextBlock)
   297  	require.NoError(t, err)
   298  
   299  	lastConf = extractSysChanLastConfig(rlf, genesisBlock)
   300  	assert.NotNil(t, lastConf)
   301  	assert.Equal(t, uint64(1), lastConf.Header.Number)
   302  }
   303  
   304  func TestSelectClusterBootBlock(t *testing.T) {
   305  	bootstrapBlock := &common.Block{Header: &common.BlockHeader{Number: 100}}
   306  	lastConfBlock := &common.Block{Header: &common.BlockHeader{Number: 100}}
   307  
   308  	clusterBoot := selectClusterBootBlock(bootstrapBlock, nil)
   309  	assert.NotNil(t, clusterBoot)
   310  	assert.Equal(t, uint64(100), clusterBoot.Header.Number)
   311  	assert.True(t, bootstrapBlock == clusterBoot)
   312  
   313  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   314  	assert.NotNil(t, clusterBoot)
   315  	assert.Equal(t, uint64(100), clusterBoot.Header.Number)
   316  	assert.True(t, bootstrapBlock == clusterBoot)
   317  
   318  	lastConfBlock.Header.Number = 200
   319  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   320  	assert.NotNil(t, clusterBoot)
   321  	assert.Equal(t, uint64(200), clusterBoot.Header.Number)
   322  	assert.True(t, lastConfBlock == clusterBoot)
   323  
   324  	bootstrapBlock.Header.Number = 300
   325  	clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock)
   326  	assert.NotNil(t, clusterBoot)
   327  	assert.Equal(t, uint64(300), clusterBoot.Header.Number)
   328  	assert.True(t, bootstrapBlock == clusterBoot)
   329  }
   330  
   331  func TestLoadLocalMSP(t *testing.T) {
   332  	t.Run("Happy", func(t *testing.T) {
   333  		localMSPDir := configtest.GetDevMspDir()
   334  		localMSP := loadLocalMSP(
   335  			&localconfig.TopLevel{
   336  				General: localconfig.General{
   337  					LocalMSPDir: localMSPDir,
   338  					LocalMSPID:  "SampleOrg",
   339  					BCCSP: &factory.FactoryOpts{
   340  						ProviderName: "SW",
   341  						SwOpts: &factory.SwOpts{
   342  							HashFamily: "SHA2",
   343  							SecLevel:   256,
   344  							Ephemeral:  true,
   345  						},
   346  					},
   347  				},
   348  			},
   349  		)
   350  		require.NotNil(t, localMSP)
   351  		id, err := localMSP.GetIdentifier()
   352  		require.NoError(t, err)
   353  		require.Equal(t, id, "SampleOrg")
   354  	})
   355  
   356  	t.Run("Error", func(t *testing.T) {
   357  		oldLogger := logger
   358  		defer func() { logger = oldLogger }()
   359  		logger, _ = floggingtest.NewTestLogger(t)
   360  
   361  		assert.Panics(t, func() {
   362  			loadLocalMSP(
   363  				&localconfig.TopLevel{
   364  					General: localconfig.General{
   365  						LocalMSPDir: "",
   366  						LocalMSPID:  "",
   367  					},
   368  				},
   369  			)
   370  		})
   371  	})
   372  }
   373  
   374  func TestInitializeMultichannelRegistrar(t *testing.T) {
   375  	cleanup := configtest.SetDevFabricConfigPath(t)
   376  	defer cleanup()
   377  	genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid")
   378  	defer os.Remove(genesisFile)
   379  
   380  	conf := genesisConfig(t, genesisFile)
   381  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   382  	assert.NoError(t, err)
   383  
   384  	signer := &server_mocks.SignerSerializer{}
   385  
   386  	t.Run("registrar with a system channel", func(t *testing.T) {
   387  		lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
   388  		assert.NoError(t, err)
   389  		bootBlock := file.New(genesisFile).GenesisBlock()
   390  		initializeBootstrapChannel(bootBlock, lf)
   391  		registrar := initializeMultichannelRegistrar(
   392  			bootBlock,
   393  			&replicationInitiator{cryptoProvider: cryptoProvider},
   394  			&cluster.PredicateDialer{},
   395  			comm.ServerConfig{},
   396  			nil,
   397  			conf,
   398  			signer,
   399  			&disabled.Provider{},
   400  			&server_mocks.HealthChecker{},
   401  			lf,
   402  			cryptoProvider,
   403  		)
   404  		assert.NotNil(t, registrar)
   405  		assert.Equal(t, "testchannelid", registrar.SystemChannelID())
   406  	})
   407  
   408  	t.Run("registrar without a system channel", func(t *testing.T) {
   409  		conf.General.BootstrapMethod = "none"
   410  		conf.General.GenesisFile = ""
   411  		lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
   412  		assert.NoError(t, err)
   413  		registrar := initializeMultichannelRegistrar(
   414  			nil,
   415  			&replicationInitiator{cryptoProvider: cryptoProvider},
   416  			&cluster.PredicateDialer{},
   417  			comm.ServerConfig{},
   418  			nil,
   419  			conf,
   420  			signer,
   421  			&disabled.Provider{},
   422  			&server_mocks.HealthChecker{},
   423  			lf,
   424  			cryptoProvider,
   425  		)
   426  		assert.NotNil(t, registrar)
   427  		assert.Empty(t, registrar.SystemChannelID())
   428  	})
   429  }
   430  
   431  func TestInitializeGrpcServer(t *testing.T) {
   432  	// get a free random port
   433  	listenAddr := func() string {
   434  		l, _ := net.Listen("tcp", "localhost:0")
   435  		l.Close()
   436  		return l.Addr().String()
   437  	}()
   438  	host := strings.Split(listenAddr, ":")[0]
   439  	port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16)
   440  	conf := &localconfig.TopLevel{
   441  		General: localconfig.General{
   442  			ListenAddress: host,
   443  			ListenPort:    uint16(port),
   444  			TLS: localconfig.TLS{
   445  				Enabled:            false,
   446  				ClientAuthRequired: false,
   447  			},
   448  		},
   449  	}
   450  	assert.NotPanics(t, func() {
   451  		grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   452  		grpcServer.Listener().Close()
   453  	})
   454  }
   455  
   456  func TestUpdateTrustedRoots(t *testing.T) {
   457  	cleanup := configtest.SetDevFabricConfigPath(t)
   458  	defer cleanup()
   459  
   460  	genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid")
   461  	defer os.Remove(genesisFile)
   462  
   463  	// get a free random port
   464  	listenAddr := func() string {
   465  		l, _ := net.Listen("tcp", "localhost:0")
   466  		l.Close()
   467  		return l.Addr().String()
   468  	}()
   469  	port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16)
   470  	conf := &localconfig.TopLevel{
   471  		General: localconfig.General{
   472  			BootstrapMethod: "file",
   473  			BootstrapFile:   genesisFile,
   474  			ListenAddress:   "localhost",
   475  			ListenPort:      uint16(port),
   476  			TLS: localconfig.TLS{
   477  				Enabled:            false,
   478  				ClientAuthRequired: false,
   479  			},
   480  		},
   481  	}
   482  	grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   483  	caMgr := &caManager{
   484  		appRootCAsByChain:     make(map[string][][]byte),
   485  		ordererRootCAsByChain: make(map[string][][]byte),
   486  	}
   487  	callback := func(bundle *channelconfig.Bundle) {
   488  		if grpcServer.MutualTLSRequired() {
   489  			t.Log("callback called")
   490  			caMgr.updateTrustedRoots(bundle, grpcServer)
   491  		}
   492  	}
   493  	lf, _, err := createLedgerFactory(conf, &disabled.Provider{})
   494  	assert.NoError(t, err)
   495  	bootBlock := file.New(genesisFile).GenesisBlock()
   496  	initializeBootstrapChannel(bootBlock, lf)
   497  	signer := &server_mocks.SignerSerializer{}
   498  
   499  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   500  	assert.NoError(t, err)
   501  
   502  	initializeMultichannelRegistrar(
   503  		bootBlock,
   504  		&replicationInitiator{cryptoProvider: cryptoProvider},
   505  		&cluster.PredicateDialer{},
   506  		comm.ServerConfig{},
   507  		nil,
   508  		genesisConfig(t, genesisFile),
   509  		signer,
   510  		&disabled.Provider{},
   511  		&server_mocks.HealthChecker{},
   512  		lf,
   513  		cryptoProvider,
   514  		callback,
   515  	)
   516  	t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"]))
   517  	t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"]))
   518  	// mutual TLS not required so no updates should have occurred
   519  	assert.Equal(t, 0, len(caMgr.appRootCAsByChain["testchannelid"]))
   520  	assert.Equal(t, 0, len(caMgr.ordererRootCAsByChain["testchannelid"]))
   521  	grpcServer.Listener().Close()
   522  
   523  	conf = &localconfig.TopLevel{
   524  		General: localconfig.General{
   525  			ListenAddress: "localhost",
   526  			ListenPort:    uint16(port),
   527  			TLS: localconfig.TLS{
   528  				Enabled:            true,
   529  				ClientAuthRequired: true,
   530  				PrivateKey:         filepath.Join(".", "testdata", "example.com", "tls", "server.key"),
   531  				Certificate:        filepath.Join(".", "testdata", "example.com", "tls", "server.crt"),
   532  			},
   533  		},
   534  	}
   535  	grpcServer = initializeGrpcServer(conf, initializeServerConfig(conf, nil))
   536  	caMgr = &caManager{
   537  		appRootCAsByChain:     make(map[string][][]byte),
   538  		ordererRootCAsByChain: make(map[string][][]byte),
   539  	}
   540  
   541  	clusterConf := initializeClusterClientConfig(conf)
   542  	predDialer := &cluster.PredicateDialer{
   543  		Config: clusterConf,
   544  	}
   545  
   546  	callback = func(bundle *channelconfig.Bundle) {
   547  		if grpcServer.MutualTLSRequired() {
   548  			t.Log("callback called")
   549  			caMgr.updateTrustedRoots(bundle, grpcServer)
   550  			caMgr.updateClusterDialer(predDialer, clusterConf.SecOpts.ServerRootCAs)
   551  		}
   552  	}
   553  	initializeMultichannelRegistrar(
   554  		bootBlock,
   555  		&replicationInitiator{cryptoProvider: cryptoProvider},
   556  		predDialer,
   557  		comm.ServerConfig{},
   558  		nil,
   559  		genesisConfig(t, genesisFile),
   560  		signer,
   561  		&disabled.Provider{},
   562  		&server_mocks.HealthChecker{},
   563  		lf,
   564  		cryptoProvider,
   565  		callback,
   566  	)
   567  	t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"]))
   568  	t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"]))
   569  	// mutual TLS is required so updates should have occurred
   570  	// we expect an intermediate and root CA for apps and orderers
   571  	assert.Equal(t, 2, len(caMgr.appRootCAsByChain["testchannelid"]))
   572  	assert.Equal(t, 2, len(caMgr.ordererRootCAsByChain["testchannelid"]))
   573  	assert.Len(t, predDialer.Config.SecOpts.ServerRootCAs, 2)
   574  	grpcServer.Listener().Close()
   575  }
   576  
   577  func TestConfigureClusterListener(t *testing.T) {
   578  	logEntries := make(chan string, 100)
   579  
   580  	allocatePort := func() uint16 {
   581  		l, err := net.Listen("tcp", "127.0.0.1:0")
   582  		assert.NoError(t, err)
   583  		_, portStr, err := net.SplitHostPort(l.Addr().String())
   584  		assert.NoError(t, err)
   585  		port, err := strconv.ParseInt(portStr, 10, 64)
   586  		assert.NoError(t, err)
   587  		assert.NoError(t, l.Close())
   588  		t.Log("picked unused port", port)
   589  		return uint16(port)
   590  	}
   591  
   592  	unUsedPort := allocatePort()
   593  
   594  	backupLogger := logger
   595  	logger = logger.With(zap.Hooks(func(entry zapcore.Entry) error {
   596  		logEntries <- entry.Message
   597  		return nil
   598  	}))
   599  
   600  	defer func() {
   601  		logger = backupLogger
   602  	}()
   603  
   604  	ca, err := tlsgen.NewCA()
   605  	assert.NoError(t, err)
   606  	serverKeyPair, err := ca.NewServerCertKeyPair("127.0.0.1")
   607  	assert.NoError(t, err)
   608  
   609  	loadPEM := func(fileName string) ([]byte, error) {
   610  		switch fileName {
   611  		case "cert":
   612  			return serverKeyPair.Cert, nil
   613  		case "key":
   614  			return serverKeyPair.Key, nil
   615  		case "ca":
   616  			return ca.CertBytes(), nil
   617  		default:
   618  			return nil, errors.New("I/O error")
   619  		}
   620  	}
   621  
   622  	for _, testCase := range []struct {
   623  		name               string
   624  		conf               *localconfig.TopLevel
   625  		generalConf        comm.ServerConfig
   626  		generalSrv         *comm.GRPCServer
   627  		shouldBeEqual      bool
   628  		expectedPanic      string
   629  		expectedLogEntries []string
   630  	}{
   631  		{
   632  			name:        "invalid certificate",
   633  			generalConf: comm.ServerConfig{},
   634  			conf: &localconfig.TopLevel{
   635  				General: localconfig.General{
   636  					Cluster: localconfig.Cluster{
   637  						ListenAddress:     "127.0.0.1",
   638  						ListenPort:        5000,
   639  						ServerPrivateKey:  "key",
   640  						ServerCertificate: "bad",
   641  						RootCAs:           []string{"ca"},
   642  					},
   643  				},
   644  			},
   645  			expectedPanic:      "Failed to load cluster server certificate from 'bad' (I/O error)",
   646  			generalSrv:         &comm.GRPCServer{},
   647  			expectedLogEntries: []string{"Failed to load cluster server certificate from 'bad' (I/O error)"},
   648  		},
   649  		{
   650  			name:        "invalid key",
   651  			generalConf: comm.ServerConfig{},
   652  			conf: &localconfig.TopLevel{
   653  				General: localconfig.General{
   654  					Cluster: localconfig.Cluster{
   655  						ListenAddress:     "127.0.0.1",
   656  						ListenPort:        5000,
   657  						ServerPrivateKey:  "bad",
   658  						ServerCertificate: "cert",
   659  						RootCAs:           []string{"ca"},
   660  					},
   661  				},
   662  			},
   663  			expectedPanic:      "Failed to load cluster server key from 'bad' (I/O error)",
   664  			generalSrv:         &comm.GRPCServer{},
   665  			expectedLogEntries: []string{"Failed to load cluster server certificate from 'bad' (I/O error)"},
   666  		},
   667  		{
   668  			name:        "invalid ca cert",
   669  			generalConf: comm.ServerConfig{},
   670  			conf: &localconfig.TopLevel{
   671  				General: localconfig.General{
   672  					Cluster: localconfig.Cluster{
   673  						ListenAddress:     "127.0.0.1",
   674  						ListenPort:        5000,
   675  						ServerPrivateKey:  "key",
   676  						ServerCertificate: "cert",
   677  						RootCAs:           []string{"bad"},
   678  					},
   679  				},
   680  			},
   681  			expectedPanic:      "Failed to load CA cert file 'bad' (I/O error)",
   682  			generalSrv:         &comm.GRPCServer{},
   683  			expectedLogEntries: []string{"Failed to load CA cert file 'bad' (I/O error)"},
   684  		},
   685  		{
   686  			name:        "bad listen address",
   687  			generalConf: comm.ServerConfig{},
   688  			conf: &localconfig.TopLevel{
   689  				General: localconfig.General{
   690  					Cluster: localconfig.Cluster{
   691  						ListenAddress:     "99.99.99.99",
   692  						ListenPort:        unUsedPort,
   693  						ServerPrivateKey:  "key",
   694  						ServerCertificate: "cert",
   695  						RootCAs:           []string{"ca"},
   696  					},
   697  				},
   698  			},
   699  			expectedPanic: fmt.Sprintf("Failed creating gRPC server on 99.99.99.99:%d due "+
   700  				"to listen tcp 99.99.99.99:%d:", unUsedPort, unUsedPort),
   701  			generalSrv: &comm.GRPCServer{},
   702  		},
   703  		{
   704  			name:        "green path",
   705  			generalConf: comm.ServerConfig{},
   706  			conf: &localconfig.TopLevel{
   707  				General: localconfig.General{
   708  					Cluster: localconfig.Cluster{
   709  						ListenAddress:     "127.0.0.1",
   710  						ListenPort:        5000,
   711  						ServerPrivateKey:  "key",
   712  						ServerCertificate: "cert",
   713  						RootCAs:           []string{"ca"},
   714  					},
   715  				},
   716  			},
   717  			generalSrv: &comm.GRPCServer{},
   718  		},
   719  	} {
   720  		t.Run(testCase.name, func(t *testing.T) {
   721  			if testCase.shouldBeEqual {
   722  				conf, srv := configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
   723  				assert.Equal(t, conf, testCase.generalConf)
   724  				assert.Equal(t, srv, testCase.generalSrv)
   725  			}
   726  
   727  			if testCase.expectedPanic != "" {
   728  				f := func() {
   729  					configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
   730  				}
   731  				assert.Contains(t, panicMsg(f), testCase.expectedPanic)
   732  			} else {
   733  				configureClusterListener(testCase.conf, testCase.generalConf, loadPEM)
   734  			}
   735  			// Ensure logged messages that are expected were all logged
   736  			var loggedMessages []string
   737  			for len(logEntries) > 0 {
   738  				logEntry := <-logEntries
   739  				loggedMessages = append(loggedMessages, logEntry)
   740  			}
   741  			assert.Subset(t, testCase.expectedLogEntries, loggedMessages)
   742  		})
   743  	}
   744  }
   745  
   746  func TestReuseListener(t *testing.T) {
   747  	t.Run("good to reuse", func(t *testing.T) {
   748  		top := &localconfig.TopLevel{General: localconfig.General{TLS: localconfig.TLS{Enabled: true}}}
   749  		require.True(t, reuseListener(top, "foo"))
   750  	})
   751  
   752  	t.Run("reuse tls disabled", func(t *testing.T) {
   753  		top := &localconfig.TopLevel{}
   754  		require.PanicsWithValue(
   755  			t,
   756  			"TLS is required for running ordering nodes of type foo.",
   757  			func() { reuseListener(top, "foo") },
   758  		)
   759  	})
   760  
   761  	t.Run("good not to reuse", func(t *testing.T) {
   762  		top := &localconfig.TopLevel{
   763  			General: localconfig.General{
   764  				Cluster: localconfig.Cluster{
   765  					ListenAddress:     "127.0.0.1",
   766  					ListenPort:        5000,
   767  					ServerPrivateKey:  "key",
   768  					ServerCertificate: "bad",
   769  				},
   770  			},
   771  		}
   772  		require.False(t, reuseListener(top, "foo"))
   773  	})
   774  
   775  	t.Run("partial config", func(t *testing.T) {
   776  		top := &localconfig.TopLevel{
   777  			General: localconfig.General{
   778  				Cluster: localconfig.Cluster{
   779  					ListenAddress:     "127.0.0.1",
   780  					ListenPort:        5000,
   781  					ServerCertificate: "bad",
   782  				},
   783  			},
   784  		}
   785  		require.PanicsWithValue(
   786  			t,
   787  			"Options: General.Cluster.ListenPort, General.Cluster.ListenAddress,"+
   788  				" General.Cluster.ServerCertificate, General.Cluster.ServerPrivateKey, should be defined altogether.",
   789  			func() { reuseListener(top, "foo") },
   790  		)
   791  	})
   792  }
   793  
   794  func TestInitializeEtcdraftConsenter(t *testing.T) {
   795  	consenters := make(map[string]consensus.Consenter)
   796  
   797  	tmpdir, err := ioutil.TempDir("", "main_test-")
   798  	require.NoError(t, err)
   799  	defer os.RemoveAll(tmpdir)
   800  	rlf, err := fileledger.New(tmpdir, &disabled.Provider{})
   801  	require.NoError(t, err)
   802  
   803  	conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   804  	genesisBlock := encoder.New(conf).GenesisBlock()
   805  
   806  	ca, _ := tlsgen.NewCA()
   807  	crt, _ := ca.NewServerCertKeyPair("127.0.0.1")
   808  
   809  	srv, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{})
   810  	assert.NoError(t, err)
   811  
   812  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   813  	assert.NoError(t, err)
   814  
   815  	initializeEtcdraftConsenter(consenters,
   816  		&localconfig.TopLevel{},
   817  		rlf,
   818  		&cluster.PredicateDialer{},
   819  		genesisBlock, &replicationInitiator{cryptoProvider: cryptoProvider},
   820  		comm.ServerConfig{
   821  			SecOpts: comm.SecureOptions{
   822  				Certificate: crt.Cert,
   823  				Key:         crt.Key,
   824  				UseTLS:      true,
   825  			},
   826  		},
   827  		srv,
   828  		&multichannel.Registrar{},
   829  		&disabled.Provider{},
   830  		cryptoProvider,
   831  	)
   832  	assert.NotNil(t, consenters["etcdraft"])
   833  }
   834  
   835  func genesisConfig(t *testing.T, genesisFile string) *localconfig.TopLevel {
   836  	t.Helper()
   837  	localMSPDir := configtest.GetDevMspDir()
   838  	return &localconfig.TopLevel{
   839  		General: localconfig.General{
   840  			BootstrapMethod: "file",
   841  			BootstrapFile:   genesisFile,
   842  			LocalMSPDir:     localMSPDir,
   843  			LocalMSPID:      "SampleOrg",
   844  			BCCSP: &factory.FactoryOpts{
   845  				ProviderName: "SW",
   846  				SwOpts: &factory.SwOpts{
   847  					HashFamily: "SHA2",
   848  					SecLevel:   256,
   849  					Ephemeral:  true,
   850  				},
   851  			},
   852  		},
   853  	}
   854  }
   855  
   856  func panicMsg(f func()) string {
   857  	var message interface{}
   858  	func() {
   859  
   860  		defer func() {
   861  			message = recover()
   862  		}()
   863  
   864  		f()
   865  
   866  	}()
   867  
   868  	return message.(string)
   869  
   870  }
   871  
   872  func TestCreateReplicator(t *testing.T) {
   873  	cleanup := configtest.SetDevFabricConfigPath(t)
   874  	defer cleanup()
   875  	bootBlock := encoder.New(genesisconfig.Load(genesisconfig.SampleDevModeSoloProfile)).GenesisBlockForChannel("system")
   876  
   877  	iterator := &deliver_mocks.BlockIterator{}
   878  	iterator.NextReturnsOnCall(0, bootBlock, common.Status_SUCCESS)
   879  	iterator.NextReturnsOnCall(1, bootBlock, common.Status_SUCCESS)
   880  
   881  	ledger := &ledger_mocks.ReadWriter{}
   882  	ledger.On("Height").Return(uint64(1))
   883  	ledger.On("Iterator", mock.Anything).Return(iterator, uint64(1))
   884  
   885  	ledgerFactory := &server_mocks.Factory{}
   886  	ledgerFactory.On("GetOrCreate", "mychannel").Return(ledger, nil)
   887  	ledgerFactory.On("ChannelIDs").Return([]string{"mychannel"})
   888  
   889  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   890  	assert.NoError(t, err)
   891  
   892  	signer := &server_mocks.SignerSerializer{}
   893  	r := createReplicator(ledgerFactory, bootBlock, &localconfig.TopLevel{}, comm.SecureOptions{}, signer, cryptoProvider)
   894  
   895  	err = r.verifierRetriever.RetrieveVerifier("mychannel").VerifyBlockSignature(nil, nil)
   896  	assert.EqualError(t, err, "implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Writers' sub-policies to be satisfied")
   897  
   898  	err = r.verifierRetriever.RetrieveVerifier("system").VerifyBlockSignature(nil, nil)
   899  	assert.NoError(t, err)
   900  }
   901  
   902  func produceGenesisFile(t *testing.T, profile, channelID string) string {
   903  	conf := genesisconfig.Load(profile, configtest.GetDevConfigDir())
   904  	f, err := ioutil.TempFile("", fmt.Sprintf("%s-genesis_block-", t.Name()))
   905  	require.NoError(t, err)
   906  	_, err = f.Write(protoutil.MarshalOrPanic(encoder.New(conf).GenesisBlockForChannel(channelID)))
   907  	require.NoError(t, err)
   908  	err = f.Close()
   909  	require.NoError(t, err)
   910  	return f.Name()
   911  }