github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/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  	"io/ioutil"
    11  	"os"
    12  	"testing"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	cb "github.com/hyperledger/fabric-protos-go/common"
    16  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    17  	"github.com/hyperledger/fabric/bccsp/sw"
    18  	"github.com/hyperledger/fabric/common/channelconfig"
    19  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    20  	"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger"
    21  	"github.com/hyperledger/fabric/common/metrics/disabled"
    22  	"github.com/hyperledger/fabric/common/policies"
    23  	"github.com/hyperledger/fabric/core/config/configtest"
    24  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    25  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    26  	"github.com/hyperledger/fabric/internal/pkg/identity"
    27  	"github.com/hyperledger/fabric/orderer/common/blockcutter"
    28  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    29  	"github.com/hyperledger/fabric/orderer/common/multichannel/mocks"
    30  	"github.com/hyperledger/fabric/orderer/consensus"
    31  	"github.com/hyperledger/fabric/protoutil"
    32  	"github.com/pkg/errors"
    33  	"github.com/stretchr/testify/assert"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  //go:generate counterfeiter -o mocks/resources.go --fake-name Resources . resources
    38  
    39  type resources interface {
    40  	channelconfig.Resources
    41  }
    42  
    43  //go:generate counterfeiter -o mocks/orderer_config.go --fake-name OrdererConfig . ordererConfig
    44  
    45  type ordererConfig interface {
    46  	channelconfig.Orderer
    47  }
    48  
    49  //go:generate counterfeiter -o mocks/orderer_capabilities.go --fake-name OrdererCapabilities . ordererCapabilities
    50  
    51  type ordererCapabilities interface {
    52  	channelconfig.OrdererCapabilities
    53  }
    54  
    55  //go:generate counterfeiter -o mocks/channel_config.go --fake-name ChannelConfig . channelConfig
    56  
    57  type channelConfig interface {
    58  	channelconfig.Channel
    59  }
    60  
    61  //go:generate counterfeiter -o mocks/channel_capabilities.go --fake-name ChannelCapabilities . channelCapabilities
    62  
    63  type channelCapabilities interface {
    64  	channelconfig.ChannelCapabilities
    65  }
    66  
    67  //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    68  
    69  type signerSerializer interface {
    70  	identity.SignerSerializer
    71  }
    72  
    73  func mockCrypto() *mocks.SignerSerializer {
    74  	return &mocks.SignerSerializer{}
    75  }
    76  
    77  func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block) (blockledger.Factory, blockledger.ReadWriter) {
    78  	rlf, err := fileledger.New(dir, &disabled.Provider{})
    79  	if err != nil {
    80  		panic(err)
    81  	}
    82  
    83  	rl, err := rlf.GetOrCreate(chainID)
    84  	if err != nil {
    85  		panic(err)
    86  	}
    87  
    88  	if genesisBlockSys != nil {
    89  		err = rl.Append(genesisBlockSys)
    90  		if err != nil {
    91  			panic(err)
    92  		}
    93  	}
    94  	return rlf, rl
    95  }
    96  
    97  func testMessageOrderAndRetrieval(maxMessageCount uint32, chainID string, chainSupport *ChainSupport, lr blockledger.ReadWriter, t *testing.T) {
    98  	messages := make([]*cb.Envelope, maxMessageCount)
    99  	for i := uint32(0); i < maxMessageCount; i++ {
   100  		messages[i] = makeNormalTx(chainID, int(i))
   101  	}
   102  	for _, message := range messages {
   103  		chainSupport.Order(message, 0)
   104  	}
   105  	it, _ := lr.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   106  	defer it.Close()
   107  	block, status := it.Next()
   108  	assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block")
   109  	for i := uint32(0); i < maxMessageCount; i++ {
   110  		assert.True(t, proto.Equal(messages[i], protoutil.ExtractEnvelopeOrPanic(block, int(i))), "Block contents wrong at index %d", i)
   111  	}
   112  }
   113  
   114  func TestConfigTx(t *testing.T) {
   115  	//system channel
   116  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   117  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   118  
   119  	// Tests for a normal chain which contains 3 config transactions and other normal transactions to make
   120  	// sure the right one returned
   121  	t.Run("GetConfigTx - ok", func(t *testing.T) {
   122  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   123  		require.NoError(t, err)
   124  		defer os.RemoveAll(tmpdir)
   125  
   126  		_, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   127  		for i := 0; i < 5; i++ {
   128  			rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", i)}))
   129  		}
   130  		rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx("testchannelid", 5)}))
   131  		ctx := makeConfigTx("testchannelid", 6)
   132  		rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{ctx}))
   133  
   134  		block := blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", 7)})
   135  		block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{Value: protoutil.MarshalOrPanic(&cb.LastConfig{Index: 7})})
   136  		rl.Append(block)
   137  
   138  		pctx := configTx(rl)
   139  		assert.True(t, proto.Equal(pctx, ctx), "Did not select most recent config transaction")
   140  	})
   141  }
   142  
   143  func TestNewRegistrar(t *testing.T) {
   144  	//system channel
   145  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   146  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   147  
   148  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   149  	assert.NoError(t, err)
   150  
   151  	// This test checks to make sure the orderer refuses to come up if it cannot find a system channel
   152  	t.Run("No system chain - failure", func(t *testing.T) {
   153  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   154  		require.NoError(t, err)
   155  		defer os.RemoveAll(tmpdir)
   156  
   157  		lf, err := fileledger.New(tmpdir, &disabled.Provider{})
   158  		require.NoError(t, err)
   159  
   160  		consenters := make(map[string]consensus.Consenter)
   161  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   162  
   163  		assert.NotPanics(t, func() {
   164  			NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters)
   165  		}, "Should not panic when starting without a system channel")
   166  	})
   167  
   168  	// This test checks to make sure that the orderer refuses to come up if there are multiple system channels
   169  	t.Run("Multiple system chains - failure", func(t *testing.T) {
   170  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   171  		require.NoError(t, err)
   172  		defer os.RemoveAll(tmpdir)
   173  
   174  		lf, err := fileledger.New(tmpdir, &disabled.Provider{})
   175  		require.NoError(t, err)
   176  
   177  		for _, id := range []string{"foo", "bar"} {
   178  			rl, err := lf.GetOrCreate(id)
   179  			assert.NoError(t, err)
   180  
   181  			err = rl.Append(encoder.New(confSys).GenesisBlockForChannel(id))
   182  			assert.NoError(t, err)
   183  		}
   184  
   185  		consenters := make(map[string]consensus.Consenter)
   186  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   187  
   188  		assert.Panics(t, func() {
   189  			NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters)
   190  		}, "Two system channels should have caused panic")
   191  	})
   192  
   193  	// This test essentially brings the entire system up and is ultimately what main.go will replicate
   194  	t.Run("Correct flow", func(t *testing.T) {
   195  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   196  		require.NoError(t, err)
   197  		defer os.RemoveAll(tmpdir)
   198  
   199  		lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   200  
   201  		consenters := make(map[string]consensus.Consenter)
   202  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   203  
   204  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   205  		manager.Initialize(consenters)
   206  
   207  		chainSupport := manager.GetChain("Fake")
   208  		assert.Nilf(t, chainSupport, "Should not have found a chain that was not created")
   209  
   210  		chainSupport = manager.GetChain("testchannelid")
   211  		assert.NotNilf(t, chainSupport, "Should have gotten chain which was initialized by ledger")
   212  
   213  		testMessageOrderAndRetrieval(confSys.Orderer.BatchSize.MaxMessageCount, "testchannelid", chainSupport, rl, t)
   214  	})
   215  }
   216  
   217  func TestCreateChain(t *testing.T) {
   218  	//system channel
   219  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   220  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   221  
   222  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   223  	assert.NoError(t, err)
   224  
   225  	t.Run("Create chain", func(t *testing.T) {
   226  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   227  		require.NoError(t, err)
   228  		defer os.RemoveAll(tmpdir)
   229  
   230  		lf, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   231  
   232  		consenters := make(map[string]consensus.Consenter)
   233  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   234  
   235  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   236  		manager.Initialize(consenters)
   237  
   238  		ledger, err := lf.GetOrCreate("mychannel")
   239  		assert.NoError(t, err)
   240  
   241  		genesisBlock := encoder.New(confSys).GenesisBlockForChannel("mychannel")
   242  		ledger.Append(genesisBlock)
   243  
   244  		// Before creating the chain, it doesn't exist
   245  		assert.Nil(t, manager.GetChain("mychannel"))
   246  		// After creating the chain, it exists
   247  		manager.CreateChain("mychannel")
   248  		chain := manager.GetChain("mychannel")
   249  		assert.NotNil(t, chain)
   250  		// A subsequent creation, replaces the chain.
   251  		manager.CreateChain("mychannel")
   252  		chain2 := manager.GetChain("mychannel")
   253  		assert.NotNil(t, chain2)
   254  		// They are not the same
   255  		assert.NotEqual(t, chain, chain2)
   256  		// The old chain is halted
   257  		_, ok := <-chain.Chain.(*mockChain).queue
   258  		assert.False(t, ok)
   259  		// The new chain is not halted: Close the channel to prove that.
   260  		close(chain2.Chain.(*mockChain).queue)
   261  	})
   262  
   263  	// This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
   264  	t.Run("New chain", func(t *testing.T) {
   265  		expectedLastConfigBlockNumber := uint64(0)
   266  		expectedLastConfigSeq := uint64(1)
   267  		newChainID := "test-new-chain"
   268  
   269  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   270  		require.NoError(t, err)
   271  		defer os.RemoveAll(tmpdir)
   272  
   273  		lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   274  
   275  		consenters := make(map[string]consensus.Consenter)
   276  		consenters[confSys.Orderer.OrdererType] = &mockConsenter{}
   277  
   278  		manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   279  		manager.Initialize(consenters)
   280  		orglessChannelConf := genesisconfig.Load(genesisconfig.SampleSingleMSPChannelProfile, configtest.GetDevConfigDir())
   281  		orglessChannelConf.Application.Organizations = nil
   282  		envConfigUpdate, err := encoder.MakeChannelCreationTransaction(newChainID, mockCrypto(), orglessChannelConf)
   283  		assert.NoError(t, err, "Constructing chain creation tx")
   284  
   285  		res, err := manager.NewChannelConfig(envConfigUpdate)
   286  		assert.NoError(t, err, "Constructing initial channel config")
   287  
   288  		configEnv, err := res.ConfigtxValidator().ProposeConfigUpdate(envConfigUpdate)
   289  		assert.NoError(t, err, "Proposing initial update")
   290  		assert.Equal(t, expectedLastConfigSeq, configEnv.GetConfig().Sequence, "Sequence of config envelope for new channel should always be set to %d", expectedLastConfigSeq)
   291  
   292  		ingressTx, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch)
   293  		assert.NoError(t, err, "Creating ingresstx")
   294  
   295  		wrapped := wrapConfigTx(ingressTx)
   296  
   297  		chainSupport := manager.GetChain(manager.SystemChannelID())
   298  		assert.NotNilf(t, chainSupport, "Could not find system channel")
   299  
   300  		chainSupport.Configure(wrapped, 0)
   301  		func() {
   302  			it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   303  			defer it.Close()
   304  			block, status := it.Next()
   305  			if status != cb.Status_SUCCESS {
   306  				t.Fatalf("Could not retrieve block")
   307  			}
   308  			if len(block.Data.Data) != 1 {
   309  				t.Fatalf("Should have had only one message in the orderer transaction block")
   310  			}
   311  
   312  			assert.True(t, proto.Equal(wrapped, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Orderer config block contains wrong transaction")
   313  		}()
   314  
   315  		chainSupport = manager.GetChain(newChainID)
   316  		if chainSupport == nil {
   317  			t.Fatalf("Should have gotten new chain which was created")
   318  		}
   319  
   320  		messages := make([]*cb.Envelope, confSys.Orderer.BatchSize.MaxMessageCount)
   321  		for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ {
   322  			messages[i] = makeNormalTx(newChainID, i)
   323  		}
   324  
   325  		for _, message := range messages {
   326  			chainSupport.Order(message, 0)
   327  		}
   328  
   329  		it, _ := chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}})
   330  		defer it.Close()
   331  		block, status := it.Next()
   332  		if status != cb.Status_SUCCESS {
   333  			t.Fatalf("Could not retrieve new chain genesis block")
   334  		}
   335  		testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber)
   336  		if len(block.Data.Data) != 1 {
   337  			t.Fatalf("Should have had only one message in the new genesis block")
   338  		}
   339  
   340  		assert.True(t, proto.Equal(ingressTx, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Genesis block contains wrong transaction")
   341  
   342  		block, status = it.Next()
   343  		if status != cb.Status_SUCCESS {
   344  			t.Fatalf("Could not retrieve block on new chain")
   345  		}
   346  		testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber)
   347  		for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ {
   348  			if !proto.Equal(protoutil.ExtractEnvelopeOrPanic(block, i), messages[i]) {
   349  				t.Errorf("Block contents wrong at index %d in new chain", i)
   350  			}
   351  		}
   352  
   353  		cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   354  		assert.NoError(t, err)
   355  		rcs := newChainSupport(manager, chainSupport.ledgerResources, consenters, mockCrypto(), blockcutter.NewMetrics(&disabled.Provider{}), cryptoProvider)
   356  		assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq")
   357  	})
   358  }
   359  
   360  func testLastConfigBlockNumber(t *testing.T, block *cb.Block, expectedBlockNumber uint64) {
   361  	metadataItem := &cb.Metadata{}
   362  	err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG], metadataItem)
   363  	assert.NoError(t, err, "Block should carry LAST_CONFIG metadata item")
   364  	lastConfig := &cb.LastConfig{}
   365  	err = proto.Unmarshal(metadataItem.Value, lastConfig)
   366  	assert.NoError(t, err, "LAST_CONFIG metadata item should carry last config value")
   367  	assert.Equal(t, expectedBlockNumber, lastConfig.Index, "LAST_CONFIG value should point to last config block")
   368  }
   369  
   370  func TestResourcesCheck(t *testing.T) {
   371  	mockOrderer := &mocks.OrdererConfig{}
   372  	mockOrdererCaps := &mocks.OrdererCapabilities{}
   373  	mockOrderer.CapabilitiesReturns(mockOrdererCaps)
   374  	mockChannel := &mocks.ChannelConfig{}
   375  	mockChannelCaps := &mocks.ChannelCapabilities{}
   376  	mockChannel.CapabilitiesReturns(mockChannelCaps)
   377  
   378  	mockResources := &mocks.Resources{}
   379  	mockResources.PolicyManagerReturns(&policies.ManagerImpl{})
   380  
   381  	t.Run("GoodResources", func(t *testing.T) {
   382  		mockResources.OrdererConfigReturns(mockOrderer, true)
   383  		mockResources.ChannelConfigReturns(mockChannel)
   384  
   385  		err := checkResources(mockResources)
   386  		assert.NoError(t, err)
   387  	})
   388  
   389  	t.Run("MissingOrdererConfigPanic", func(t *testing.T) {
   390  		mockResources.OrdererConfigReturns(nil, false)
   391  
   392  		err := checkResources(mockResources)
   393  		assert.Error(t, err)
   394  		assert.Regexp(t, "config does not contain orderer config", err.Error())
   395  	})
   396  
   397  	t.Run("MissingOrdererCapability", func(t *testing.T) {
   398  		mockResources.OrdererConfigReturns(mockOrderer, true)
   399  		mockOrdererCaps.SupportedReturns(errors.New("An error"))
   400  
   401  		err := checkResources(mockResources)
   402  		assert.Error(t, err)
   403  		assert.Regexp(t, "config requires unsupported orderer capabilities:", err.Error())
   404  
   405  		// reset
   406  		mockOrdererCaps.SupportedReturns(nil)
   407  	})
   408  
   409  	t.Run("MissingChannelCapability", func(t *testing.T) {
   410  		mockChannelCaps.SupportedReturns(errors.New("An error"))
   411  
   412  		err := checkResources(mockResources)
   413  		assert.Error(t, err)
   414  		assert.Regexp(t, "config requires unsupported channel capabilities:", err.Error())
   415  	})
   416  
   417  	t.Run("MissingOrdererConfigPanic", func(t *testing.T) {
   418  		mockResources.OrdererConfigReturns(nil, false)
   419  
   420  		assert.Panics(t, func() {
   421  			checkResourcesOrPanic(mockResources)
   422  		})
   423  	})
   424  }
   425  
   426  // The registrar's BroadcastChannelSupport implementation should reject message types which should not be processed directly.
   427  func TestBroadcastChannelSupport(t *testing.T) {
   428  	// system channel
   429  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   430  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   431  
   432  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   433  	assert.NoError(t, err)
   434  
   435  	t.Run("Rejection", func(t *testing.T) {
   436  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   437  		require.NoError(t, err)
   438  		defer os.RemoveAll(tmpdir)
   439  
   440  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   441  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}}
   442  		registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   443  		registrar.Initialize(mockConsenters)
   444  		randomValue := 1
   445  		configTx := makeConfigTx("testchannelid", randomValue)
   446  		_, _, _, err = registrar.BroadcastChannelSupport(configTx)
   447  		assert.Error(t, err, "Messages of type HeaderType_CONFIG should return an error.")
   448  	})
   449  
   450  	t.Run("No system channel", func(t *testing.T) {
   451  		tmpdir, err := ioutil.TempDir("", "registrar_test-")
   452  		require.NoError(t, err)
   453  		defer os.RemoveAll(tmpdir)
   454  
   455  		ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil)
   456  		mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}}
   457  		config := localconfig.TopLevel{}
   458  		config.General.BootstrapMethod = "none"
   459  		config.General.GenesisFile = ""
   460  		registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider)
   461  		registrar.Initialize(mockConsenters)
   462  		configTx := makeConfigTxFull("testchannelid", 1)
   463  		_, _, _, err = registrar.BroadcastChannelSupport(configTx)
   464  		assert.Error(t, err)
   465  		assert.Equal(t, "channel creation request not allowed because the orderer system channel is not yet defined", err.Error())
   466  	})
   467  }