github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/orderer/common/multichannel/registrar_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package multichannel
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path"
    14  	"testing"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	cb "github.com/hyperledger/fabric-protos-go/common"
    18  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    19  	"github.com/osdi23p228/fabric/bccsp/sw"
    20  	"github.com/osdi23p228/fabric/common/channelconfig"
    21  	"github.com/osdi23p228/fabric/common/crypto/tlsgen"
    22  	"github.com/osdi23p228/fabric/common/ledger/blockledger"
    23  	"github.com/osdi23p228/fabric/common/ledger/blockledger/fileledger"
    24  	"github.com/osdi23p228/fabric/common/metrics/disabled"
    25  	"github.com/osdi23p228/fabric/common/policies"
    26  	"github.com/osdi23p228/fabric/core/config/configtest"
    27  	"github.com/osdi23p228/fabric/internal/configtxgen/encoder"
    28  	"github.com/osdi23p228/fabric/internal/configtxgen/genesisconfig"
    29  	"github.com/osdi23p228/fabric/internal/pkg/identity"
    30  	"github.com/osdi23p228/fabric/orderer/common/blockcutter"
    31  	"github.com/osdi23p228/fabric/orderer/common/localconfig"
    32  	"github.com/osdi23p228/fabric/orderer/common/multichannel/mocks"
    33  	"github.com/osdi23p228/fabric/orderer/common/types"
    34  	"github.com/osdi23p228/fabric/orderer/consensus"
    35  	"github.com/osdi23p228/fabric/protoutil"
    36  	"github.com/pkg/errors"
    37  	"github.com/stretchr/testify/assert"
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  //go:generate counterfeiter -o mocks/resources.go --fake-name Resources . resources
    42  
    43  type resources interface {
    44  	channelconfig.Resources
    45  }
    46  
    47  //go:generate counterfeiter -o mocks/orderer_config.go --fake-name OrdererConfig . ordererConfig
    48  
    49  type ordererConfig interface {
    50  	channelconfig.Orderer
    51  }
    52  
    53  //go:generate counterfeiter -o mocks/orderer_capabilities.go --fake-name OrdererCapabilities . ordererCapabilities
    54  
    55  type ordererCapabilities interface {
    56  	channelconfig.OrdererCapabilities
    57  }
    58  
    59  //go:generate counterfeiter -o mocks/channel_config.go --fake-name ChannelConfig . channelConfig
    60  
    61  type channelConfig interface {
    62  	channelconfig.Channel
    63  }
    64  
    65  //go:generate counterfeiter -o mocks/channel_capabilities.go --fake-name ChannelCapabilities . channelCapabilities
    66  
    67  type channelCapabilities interface {
    68  	channelconfig.ChannelCapabilities
    69  }
    70  
    71  //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    72  
    73  type signerSerializer interface {
    74  	identity.SignerSerializer
    75  }
    76  
    77  func mockCrypto() *mocks.SignerSerializer {
    78  	return &mocks.SignerSerializer{}
    79  }
    80  
    81  func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block) (blockledger.Factory, blockledger.ReadWriter) {
    82  	rlf, err := fileledger.New(dir, &disabled.Provider{})
    83  	if err != nil {
    84  		panic(err)
    85  	}
    86  
    87  	rl, err := rlf.GetOrCreate(chainID)
    88  	if err != nil {
    89  		panic(err)
    90  	}
    91  
    92  	if genesisBlockSys != nil {
    93  		err = rl.Append(genesisBlockSys)
    94  		if err != nil {
    95  			panic(err)
    96  		}
    97  	}
    98  	return rlf, rl
    99  }
   100  
   101  func testMessageOrderAndRetrieval(maxMessageCount uint32, chainID string, chainSupport *ChainSupport, lr blockledger.ReadWriter, t *testing.T) {
   102  	messages := make([]*cb.Envelope, maxMessageCount)
   103  	for i := uint32(0); i < maxMessageCount; i++ {
   104  		messages[i] = makeNormalTx(chainID, int(i))
   105  	}
   106  	for _, message := range messages {
   107  		chainSupport.Order(message, 0)
   108  	}
   109  	it, _ := lr.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   110  	defer it.Close()
   111  	block, status := it.Next()
   112  	assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block")
   113  	for i := uint32(0); i < maxMessageCount; i++ {
   114  		assert.True(t, proto.Equal(messages[i], protoutil.ExtractEnvelopeOrPanic(block, int(i))), "Block contents wrong at index %d", i)
   115  	}
   116  }
   117  
   118  func TestConfigTx(t *testing.T) {
   119  	// system channel
   120  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   121  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   122  
   123  	// Tests for a normal channel which contains 3 config transactions and other
   124  	// normal transactions to make sure the right one returned
   125  	t.Run("GetConfigTx - ok", func(t *testing.T) {
   126  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   127  		require.NoError(t, err)
   128  		defer os.RemoveAll(tmpdir)
   129  
   130  		_, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   131  		for i := 0; i < 5; i++ {
   132  			rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", i)}))
   133  		}
   134  		rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx("testchannelid", 5)}))
   135  		ctx := makeConfigTx("testchannelid", 6)
   136  		rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{ctx}))
   137  
   138  		// block with LAST_CONFIG metadata in SIGNATURES field
   139  		block := blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", 7)})
   140  		blockSignatureValue := protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{
   141  			LastConfig: &cb.LastConfig{Index: 7},
   142  		})
   143  		block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{Value: blockSignatureValue})
   144  		rl.Append(block)
   145  
   146  		pctx := configTx(rl)
   147  		assert.True(t, proto.Equal(pctx, ctx), "Did not select most recent config transaction")
   148  	})
   149  }
   150  
   151  func TestNewRegistrar(t *testing.T) {
   152  	//system channel
   153  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   154  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   155  
   156  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   157  	assert.NoError(t, err)
   158  
   159  	// This test checks to make sure the orderer can come up if it cannot find any chains
   160  	t.Run("No chains", func(t *testing.T) {
   161  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   162  		require.NoError(t, err)
   163  		defer os.RemoveAll(tmpdir)
   164  
   165  		lf, err := fileledger.New(tmpdir, &disabled.Provider{})
   166  		require.NoError(t, err)
   167  
   168  		consenters := make(map[string]consensus.Consenter)
   169  		consenters["etcdraft"] = &mockConsenter{}
   170  
   171  		var manager *Registrar
   172  		assert.NotPanics(t, func() {
   173  			manager = NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   174  			manager.Initialize(consenters)
   175  		}, "Should not panic when starting without a system channel")
   176  		require.NotNil(t, manager)
   177  		list := manager.ChannelList()
   178  		assert.Equal(t, types.ChannelList{}, list)
   179  		info, err := manager.ChannelInfo("my-channel")
   180  		assert.EqualError(t, err, types.ErrChannelNotExist.Error())
   181  		assert.Equal(t, types.ChannelInfo{}, info)
   182  	})
   183  
   184  	// This test checks to make sure that the orderer refuses to come up if there are multiple system channels
   185  	t.Run("Multiple system chains - failure", func(t *testing.T) {
   186  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   187  		require.NoError(t, err)
   188  		defer os.RemoveAll(tmpdir)
   189  
   190  		lf, err := fileledger.New(tmpdir, &disabled.Provider{})
   191  		require.NoError(t, err)
   192  
   193  		for _, id := range []string{"foo", "bar"} {
   194  			rl, err := lf.GetOrCreate(id)
   195  			assert.NoError(t, err)
   196  
   197  			err = rl.Append(encoder.New(confSys).GenesisBlockForChannel(id))
   198  			assert.NoError(t, err)
   199  		}
   200  
   201  		consenters := make(map[string]consensus.Consenter)
   202  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   203  
   204  		assert.Panics(t, func() {
   205  			NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters)
   206  		}, "Two system channels should have caused panic")
   207  	})
   208  
   209  	// This test essentially brings the entire system up and is ultimately what main.go will replicate
   210  	t.Run("Correct flow with system channel", func(t *testing.T) {
   211  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   212  		require.NoError(t, err)
   213  		defer os.RemoveAll(tmpdir)
   214  
   215  		lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   216  
   217  		consenters := make(map[string]consensus.Consenter)
   218  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   219  
   220  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   221  		manager.Initialize(consenters)
   222  
   223  		chainSupport := manager.GetChain("Fake")
   224  		assert.Nilf(t, chainSupport, "Should not have found a chain that was not created")
   225  
   226  		chainSupport = manager.GetChain("testchannelid")
   227  		assert.NotNilf(t, chainSupport, "Should have gotten chain which was initialized by ledger")
   228  
   229  		list := manager.ChannelList()
   230  		require.NotNil(t, list.SystemChannel)
   231  
   232  		assert.Equal(
   233  			t,
   234  			types.ChannelList{
   235  				SystemChannel: &types.ChannelInfoShort{Name: "testchannelid", URL: ""},
   236  				Channels:      nil},
   237  			list,
   238  		)
   239  
   240  		info, err := manager.ChannelInfo("testchannelid")
   241  		assert.NoError(t, err)
   242  		assert.Equal(t,
   243  			types.ChannelInfo{Name: "testchannelid", URL: "", ClusterRelation: "none", Status: "active", Height: 1},
   244  			info,
   245  		)
   246  
   247  		testMessageOrderAndRetrieval(confSys.Orderer.BatchSize.MaxMessageCount, "testchannelid", chainSupport, rl, t)
   248  	})
   249  }
   250  
   251  func TestCreateChain(t *testing.T) {
   252  	//system channel
   253  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   254  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   255  
   256  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   257  	assert.NoError(t, err)
   258  
   259  	t.Run("Create chain", func(t *testing.T) {
   260  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   261  		require.NoError(t, err)
   262  		defer os.RemoveAll(tmpdir)
   263  
   264  		lf, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   265  
   266  		consenters := make(map[string]consensus.Consenter)
   267  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{cluster: true}
   268  
   269  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   270  		manager.Initialize(consenters)
   271  
   272  		ledger, err := lf.GetOrCreate("mychannel")
   273  		assert.NoError(t, err)
   274  
   275  		genesisBlock := encoder.New(confSys).GenesisBlockForChannel("mychannel")
   276  		ledger.Append(genesisBlock)
   277  
   278  		// Before creating the chain, it doesn't exist
   279  		assert.Nil(t, manager.GetChain("mychannel"))
   280  		// After creating the chain, it exists
   281  		manager.CreateChain("mychannel")
   282  		chain := manager.GetChain("mychannel")
   283  		assert.NotNil(t, chain)
   284  
   285  		list := manager.ChannelList()
   286  		assert.Equal(
   287  			t,
   288  			types.ChannelList{
   289  				SystemChannel: &types.ChannelInfoShort{Name: "testchannelid", URL: ""},
   290  				Channels:      []types.ChannelInfoShort{{Name: "mychannel", URL: ""}}},
   291  			list,
   292  		)
   293  
   294  		info, err := manager.ChannelInfo("testchannelid")
   295  		assert.NoError(t, err)
   296  		assert.Equal(t,
   297  			types.ChannelInfo{Name: "testchannelid", URL: "", ClusterRelation: types.ClusterRelationMember, Status: types.StatusActive, Height: 1},
   298  			info,
   299  		)
   300  
   301  		info, err = manager.ChannelInfo("mychannel")
   302  		assert.NoError(t, err)
   303  		assert.Equal(t,
   304  			types.ChannelInfo{Name: "mychannel", URL: "", ClusterRelation: types.ClusterRelationMember, Status: types.StatusActive, Height: 1},
   305  			info,
   306  		)
   307  
   308  		// A subsequent creation, replaces the chain.
   309  		manager.CreateChain("mychannel")
   310  		chain2 := manager.GetChain("mychannel")
   311  		assert.NotNil(t, chain2)
   312  		// They are not the same
   313  		assert.NotEqual(t, chain, chain2)
   314  		// The old chain is halted
   315  		_, ok := <-chain.Chain.(*mockChainCluster).queue
   316  		assert.False(t, ok)
   317  
   318  		// The new chain is not halted: Close the channel to prove that.
   319  		close(chain2.Chain.(*mockChainCluster).queue)
   320  	})
   321  
   322  	// This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
   323  	t.Run("New chain", func(t *testing.T) {
   324  		expectedLastConfigSeq := uint64(1)
   325  		newChainID := "test-new-chain"
   326  
   327  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   328  		require.NoError(t, err)
   329  		defer os.RemoveAll(tmpdir)
   330  
   331  		lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   332  
   333  		consenters := make(map[string]consensus.Consenter)
   334  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   335  
   336  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   337  		manager.Initialize(consenters)
   338  		orglessChannelConf := genesisconfig.Load(genesisconfig.SampleSingleMSPChannelProfile, configtest.GetDevConfigDir())
   339  		orglessChannelConf.Application.Organizations = nil
   340  		envConfigUpdate, err := encoder.MakeChannelCreationTransaction(newChainID, mockCrypto(), orglessChannelConf)
   341  		assert.NoError(t, err, "Constructing chain creation tx")
   342  
   343  		res, err := manager.NewChannelConfig(envConfigUpdate)
   344  		assert.NoError(t, err, "Constructing initial channel config")
   345  
   346  		configEnv, err := res.ConfigtxValidator().ProposeConfigUpdate(envConfigUpdate)
   347  		assert.NoError(t, err, "Proposing initial update")
   348  		assert.Equal(t, expectedLastConfigSeq, configEnv.GetConfig().Sequence, "Sequence of config envelope for new channel should always be set to %d", expectedLastConfigSeq)
   349  
   350  		ingressTx, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch)
   351  		assert.NoError(t, err, "Creating ingresstx")
   352  
   353  		wrapped := wrapConfigTx(ingressTx)
   354  
   355  		chainSupport := manager.GetChain(manager.SystemChannelID())
   356  		assert.NotNilf(t, chainSupport, "Could not find system channel")
   357  
   358  		chainSupport.Configure(wrapped, 0)
   359  		func() {
   360  			it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   361  			defer it.Close()
   362  			block, status := it.Next()
   363  			if status != cb.Status_SUCCESS {
   364  				t.Fatalf("Could not retrieve block")
   365  			}
   366  			if len(block.Data.Data) != 1 {
   367  				t.Fatalf("Should have had only one message in the orderer transaction block")
   368  			}
   369  
   370  			assert.True(t, proto.Equal(wrapped, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Orderer config block contains wrong transaction")
   371  		}()
   372  
   373  		chainSupport = manager.GetChain(newChainID)
   374  		if chainSupport == nil {
   375  			t.Fatalf("Should have gotten new chain which was created")
   376  		}
   377  
   378  		messages := make([]*cb.Envelope, confSys.Orderer.BatchSize.MaxMessageCount)
   379  		for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ {
   380  			messages[i] = makeNormalTx(newChainID, i)
   381  		}
   382  
   383  		for _, message := range messages {
   384  			chainSupport.Order(message, 0)
   385  		}
   386  
   387  		it, _ := chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}})
   388  		defer it.Close()
   389  		block, status := it.Next()
   390  		if status != cb.Status_SUCCESS {
   391  			t.Fatalf("Could not retrieve new chain genesis block")
   392  		}
   393  		if len(block.Data.Data) != 1 {
   394  			t.Fatalf("Should have had only one message in the new genesis block")
   395  		}
   396  
   397  		assert.True(t, proto.Equal(ingressTx, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Genesis block contains wrong transaction")
   398  
   399  		block, status = it.Next()
   400  		if status != cb.Status_SUCCESS {
   401  			t.Fatalf("Could not retrieve block on new chain")
   402  		}
   403  		for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ {
   404  			if !proto.Equal(protoutil.ExtractEnvelopeOrPanic(block, i), messages[i]) {
   405  				t.Errorf("Block contents wrong at index %d in new chain", i)
   406  			}
   407  		}
   408  
   409  		cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   410  		assert.NoError(t, err)
   411  		rcs, err := newChainSupport(manager, chainSupport.ledgerResources, consenters, mockCrypto(), blockcutter.NewMetrics(&disabled.Provider{}), cryptoProvider)
   412  		assert.NoError(t, err)
   413  		assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq")
   414  	})
   415  }
   416  
   417  func TestResourcesCheck(t *testing.T) {
   418  	mockOrderer := &mocks.OrdererConfig{}
   419  	mockOrdererCaps := &mocks.OrdererCapabilities{}
   420  	mockOrderer.CapabilitiesReturns(mockOrdererCaps)
   421  	mockChannel := &mocks.ChannelConfig{}
   422  	mockChannelCaps := &mocks.ChannelCapabilities{}
   423  	mockChannel.CapabilitiesReturns(mockChannelCaps)
   424  
   425  	mockResources := &mocks.Resources{}
   426  	mockResources.PolicyManagerReturns(&policies.ManagerImpl{})
   427  
   428  	t.Run("GoodResources", func(t *testing.T) {
   429  		mockResources.OrdererConfigReturns(mockOrderer, true)
   430  		mockResources.ChannelConfigReturns(mockChannel)
   431  
   432  		err := checkResources(mockResources)
   433  		assert.NoError(t, err)
   434  	})
   435  
   436  	t.Run("MissingOrdererConfigPanic", func(t *testing.T) {
   437  		mockResources.OrdererConfigReturns(nil, false)
   438  
   439  		err := checkResources(mockResources)
   440  		assert.Error(t, err)
   441  		assert.Regexp(t, "config does not contain orderer config", err.Error())
   442  	})
   443  
   444  	t.Run("MissingOrdererCapability", func(t *testing.T) {
   445  		mockResources.OrdererConfigReturns(mockOrderer, true)
   446  		mockOrdererCaps.SupportedReturns(errors.New("An error"))
   447  
   448  		err := checkResources(mockResources)
   449  		assert.Error(t, err)
   450  		assert.Regexp(t, "config requires unsupported orderer capabilities:", err.Error())
   451  
   452  		// reset
   453  		mockOrdererCaps.SupportedReturns(nil)
   454  	})
   455  
   456  	t.Run("MissingChannelCapability", func(t *testing.T) {
   457  		mockChannelCaps.SupportedReturns(errors.New("An error"))
   458  
   459  		err := checkResources(mockResources)
   460  		assert.Error(t, err)
   461  		assert.Regexp(t, "config requires unsupported channel capabilities:", err.Error())
   462  	})
   463  
   464  	t.Run("MissingOrdererConfigPanic", func(t *testing.T) {
   465  		mockResources.OrdererConfigReturns(nil, false)
   466  
   467  		assert.Panics(t, func() {
   468  			checkResourcesOrPanic(mockResources)
   469  		})
   470  	})
   471  }
   472  
   473  // The registrar's BroadcastChannelSupport implementation should reject message types which should not be processed directly.
   474  func TestBroadcastChannelSupport(t *testing.T) {
   475  	// system channel
   476  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   477  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   478  
   479  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   480  	assert.NoError(t, err)
   481  
   482  	t.Run("Rejection", func(t *testing.T) {
   483  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   484  		require.NoError(t, err)
   485  		defer os.RemoveAll(tmpdir)
   486  
   487  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   488  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}}
   489  		registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   490  		registrar.Initialize(mockConsenters)
   491  		randomValue := 1
   492  		configTx := makeConfigTx("testchannelid", randomValue)
   493  		_, _, _, err = registrar.BroadcastChannelSupport(configTx)
   494  		assert.Error(t, err, "Messages of type HeaderType_CONFIG should return an error.")
   495  	})
   496  
   497  	t.Run("No system channel", func(t *testing.T) {
   498  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   499  		require.NoError(t, err)
   500  		defer os.RemoveAll(tmpdir)
   501  
   502  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   503  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}, "etcdraft": &mockConsenter{}}
   504  		config := localconfig.TopLevel{}
   505  		config.General.BootstrapMethod = "none"
   506  		config.General.GenesisFile = ""
   507  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   508  		registrar.Initialize(mockConsenters)
   509  		configTx := makeConfigTxFull("testchannelid", 1)
   510  		_, _, _, err = registrar.BroadcastChannelSupport(configTx)
   511  		assert.Error(t, err)
   512  		assert.Equal(t, "channel creation request not allowed because the orderer system channel is not defined", err.Error())
   513  	})
   514  }
   515  
   516  func TestRegistrar_JoinChannel(t *testing.T) {
   517  	// system channel
   518  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   519  	genesisBlockSys := encoder.New(confSys).GenesisBlockForChannel("sys-channel")
   520  	confApp := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   521  	confApp.Consortiums = nil
   522  	confApp.Consortium = ""
   523  	genesisBlockApp := encoder.New(confApp).GenesisBlockForChannel("my-channel")
   524  
   525  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   526  	assert.NoError(t, err)
   527  
   528  	t.Run("Reject join when system channel exists", func(t *testing.T) {
   529  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   530  		require.NoError(t, err)
   531  		defer os.RemoveAll(tmpdir)
   532  
   533  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "sys-channel", genesisBlockSys)
   534  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}}
   535  		registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   536  		registrar.Initialize(mockConsenters)
   537  
   538  		info, err := registrar.JoinChannel("some-app-channel", &cb.Block{}, true)
   539  		assert.EqualError(t, err, "system channel exists")
   540  		assert.Equal(t, types.ChannelInfo{}, info)
   541  	})
   542  
   543  	t.Run("Reject join when channel exists", func(t *testing.T) {
   544  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   545  		require.NoError(t, err)
   546  		defer os.RemoveAll(tmpdir)
   547  
   548  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   549  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}, "etcdraft": &mockConsenter{}}
   550  		config := localconfig.TopLevel{}
   551  		config.General.BootstrapMethod = "none"
   552  		config.General.GenesisFile = ""
   553  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   554  		registrar.Initialize(mockConsenters)
   555  
   556  		ledger, err := ledgerFactory.GetOrCreate("my-channel")
   557  		assert.NoError(t, err)
   558  		ledger.Append(genesisBlockApp)
   559  
   560  		// Before creating the chain, it doesn't exist
   561  		assert.Nil(t, registrar.GetChain("my-channel"))
   562  		// After creating the chain, it exists
   563  		registrar.CreateChain("my-channel")
   564  		assert.NotNil(t, registrar.GetChain("my-channel"))
   565  
   566  		info, err := registrar.JoinChannel("my-channel", &cb.Block{}, true)
   567  		assert.EqualError(t, err, "channel already exists")
   568  		assert.Equal(t, types.ChannelInfo{}, info)
   569  	})
   570  
   571  	t.Run("Reject system channel join when app channels exist", func(t *testing.T) {
   572  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   573  		require.NoError(t, err)
   574  		defer os.RemoveAll(tmpdir)
   575  
   576  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   577  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}, "etcdraft": &mockConsenter{}}
   578  		config := localconfig.TopLevel{}
   579  		config.General.BootstrapMethod = "none"
   580  		config.General.GenesisFile = ""
   581  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   582  		registrar.Initialize(mockConsenters)
   583  
   584  		ledger, err := ledgerFactory.GetOrCreate("my-channel")
   585  		assert.NoError(t, err)
   586  		ledger.Append(genesisBlockApp)
   587  
   588  		// Before creating the chain, it doesn't exist
   589  		assert.Nil(t, registrar.GetChain("my-channel"))
   590  		// After creating the chain, it exists
   591  		registrar.CreateChain("my-channel")
   592  		assert.NotNil(t, registrar.GetChain("my-channel"))
   593  
   594  		info, err := registrar.JoinChannel("sys-channel", &cb.Block{}, false)
   595  		assert.EqualError(t, err, "application channels already exist")
   596  		assert.Equal(t, types.ChannelInfo{}, info)
   597  	})
   598  
   599  	t.Run("no etcdraft consenter without system channel", func(t *testing.T) {
   600  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   601  		require.NoError(t, err)
   602  		defer os.RemoveAll(tmpdir)
   603  
   604  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   605  		mockConsenters := map[string]consensus.Consenter{"not-raft": &mockConsenter{}}
   606  
   607  		config := localconfig.TopLevel{}
   608  		config.General.BootstrapMethod = "none"
   609  		config.General.GenesisFile = ""
   610  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   611  
   612  		assert.Panics(t, func() { registrar.Initialize(mockConsenters) })
   613  	})
   614  
   615  	t.Run("Join app channel as member without on boarding", func(t *testing.T) {
   616  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   617  		require.NoError(t, err)
   618  		defer os.RemoveAll(tmpdir)
   619  
   620  		tlsCA, _ := tlsgen.NewCA()
   621  
   622  		confAppRaft := genesisconfig.Load(genesisconfig.SampleDevModeEtcdRaftProfile, configtest.GetDevConfigDir())
   623  		confAppRaft.Consortiums = nil
   624  		confAppRaft.Consortium = ""
   625  		generateCertificates(t, confAppRaft, tlsCA, tmpdir)
   626  		bootstrapper, err := encoder.NewBootstrapper(confAppRaft)
   627  		require.NoError(t, err, "cannot create bootstrapper")
   628  		genesisBlockAppRaft := bootstrapper.GenesisBlockForChannel("my-raft-channel")
   629  		require.NotNil(t, genesisBlockAppRaft)
   630  
   631  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   632  		mockConsenters := map[string]consensus.Consenter{confAppRaft.Orderer.OrdererType: &mockConsenter{cluster: true}}
   633  		config := localconfig.TopLevel{}
   634  		config.General.BootstrapMethod = "none"
   635  		config.General.GenesisFile = ""
   636  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   637  		registrar.Initialize(mockConsenters)
   638  
   639  		// Before join the chain, it doesn't exist
   640  		assert.Nil(t, registrar.GetChain("my-raft-channel"))
   641  
   642  		info, err := registrar.JoinChannel("my-raft-channel", genesisBlockAppRaft, true)
   643  		assert.NoError(t, err)
   644  		assert.Equal(t, types.ChannelInfo{Name: "my-raft-channel", URL: "", ClusterRelation: "member", Status: "active", Height: 0x1}, info)
   645  		// After creating the chain, it exists
   646  		assert.NotNil(t, registrar.GetChain("my-raft-channel"))
   647  	})
   648  }
   649  
   650  func generateCertificates(t *testing.T, confAppRaft *genesisconfig.Profile, tlsCA tlsgen.CA, certDir string) {
   651  	for i, c := range confAppRaft.Orderer.EtcdRaft.Consenters {
   652  		srvC, err := tlsCA.NewServerCertKeyPair(c.Host)
   653  		require.NoError(t, err)
   654  		srvP := path.Join(certDir, fmt.Sprintf("server%d.crt", i))
   655  		err = ioutil.WriteFile(srvP, srvC.Cert, 0644)
   656  		require.NoError(t, err)
   657  
   658  		clnC, err := tlsCA.NewClientCertKeyPair()
   659  		require.NoError(t, err)
   660  		clnP := path.Join(certDir, fmt.Sprintf("client%d.crt", i))
   661  		err = ioutil.WriteFile(clnP, clnC.Cert, 0644)
   662  		require.NoError(t, err)
   663  
   664  		c.ServerTlsCert = []byte(srvP)
   665  		c.ClientTlsCert = []byte(clnP)
   666  	}
   667  }