github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/multichain/manager_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package multichain
     8  
     9  import (
    10  	"fmt"
    11  	"reflect"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hyperledger/fabric/common/config"
    17  	"github.com/hyperledger/fabric/common/configtx"
    18  	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
    19  	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
    20  	mockcrypto "github.com/hyperledger/fabric/common/mocks/crypto"
    21  	"github.com/hyperledger/fabric/msp"
    22  	"github.com/hyperledger/fabric/orderer/ledger"
    23  	ramledger "github.com/hyperledger/fabric/orderer/ledger/ram"
    24  	cb "github.com/hyperledger/fabric/protos/common"
    25  	ab "github.com/hyperledger/fabric/protos/orderer"
    26  	"github.com/hyperledger/fabric/protos/utils"
    27  
    28  	mmsp "github.com/hyperledger/fabric/common/mocks/msp"
    29  	logging "github.com/op/go-logging"
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  var conf, singleMSPConf, noConsortiumConf *genesisconfig.Profile
    34  var genesisBlock, singleMSPGenesisBlock, noConsortiumGenesisBlock *cb.Block
    35  var mockSigningIdentity msp.SigningIdentity
    36  
    37  const NoConsortiumChain = "no-consortium-chain"
    38  
    39  func init() {
    40  	logging.SetLevel(logging.DEBUG, "")
    41  	mockSigningIdentity, _ = mmsp.NewNoopMsp().GetDefaultSigningIdentity()
    42  
    43  	conf = genesisconfig.Load(genesisconfig.SampleInsecureProfile)
    44  	genesisBlock = provisional.New(conf).GenesisBlock()
    45  
    46  	singleMSPConf = genesisconfig.Load(genesisconfig.SampleSingleMSPSoloProfile)
    47  	singleMSPGenesisBlock = provisional.New(singleMSPConf).GenesisBlock()
    48  
    49  	noConsortiumConf = genesisconfig.Load("SampleNoConsortium")
    50  	noConsortiumGenesisBlock = provisional.New(noConsortiumConf).GenesisBlockForChannel(NoConsortiumChain)
    51  }
    52  
    53  func mockCrypto() *mockCryptoHelper {
    54  	return &mockCryptoHelper{LocalSigner: mockcrypto.FakeLocalSigner}
    55  }
    56  
    57  type mockCryptoHelper struct {
    58  	*mockcrypto.LocalSigner
    59  }
    60  
    61  func (mch mockCryptoHelper) VerifySignature(sd *cb.SignedData) error {
    62  	return nil
    63  }
    64  
    65  func NewRAMLedgerAndFactory(maxSize int) (ledger.Factory, ledger.ReadWriter) {
    66  	rlf := ramledger.New(10)
    67  	rl, err := rlf.GetOrCreate(provisional.TestChainID)
    68  	if err != nil {
    69  		panic(err)
    70  	}
    71  	err = rl.Append(genesisBlock)
    72  	if err != nil {
    73  		panic(err)
    74  	}
    75  	return rlf, rl
    76  }
    77  
    78  func NewRAMLedgerAndFactoryWithMSP() (ledger.Factory, ledger.ReadWriter) {
    79  	rlf := ramledger.New(10)
    80  
    81  	rl, err := rlf.GetOrCreate(provisional.TestChainID)
    82  	if err != nil {
    83  		panic(err)
    84  	}
    85  	err = rl.Append(singleMSPGenesisBlock)
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	return rlf, rl
    90  }
    91  
    92  func NewRAMLedger(maxSize int) ledger.ReadWriter {
    93  	_, rl := NewRAMLedgerAndFactory(maxSize)
    94  	return rl
    95  }
    96  
    97  // Tests for a normal chain which contains 3 config transactions and other normal transactions to make sure the right one returned
    98  func TestGetConfigTx(t *testing.T) {
    99  	rl := NewRAMLedger(10)
   100  	for i := 0; i < 5; i++ {
   101  		rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, i)}))
   102  	}
   103  	rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)}))
   104  	ctx := makeConfigTx(provisional.TestChainID, 6)
   105  	rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{ctx}))
   106  
   107  	block := ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)})
   108  	block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 7})})
   109  	rl.Append(block)
   110  
   111  	pctx := getConfigTx(rl)
   112  	assert.Equal(t, pctx, ctx, "Did not select most recent config transaction")
   113  }
   114  
   115  // Tests a chain which contains blocks with multi-transactions mixed with config txs, and a single tx which is not a config tx, none count as config blocks so nil should return
   116  func TestGetConfigTxFailure(t *testing.T) {
   117  	rl := NewRAMLedger(10)
   118  	for i := 0; i < 10; i++ {
   119  		rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{
   120  			makeNormalTx(provisional.TestChainID, i),
   121  			makeConfigTx(provisional.TestChainID, i),
   122  		}))
   123  	}
   124  	rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)}))
   125  	assert.Panics(t, func() { getConfigTx(rl) }, "Should have panicked because there was no config tx")
   126  
   127  	block := ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 12)})
   128  	block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = []byte("bad metadata")
   129  	assert.Panics(t, func() { getConfigTx(rl) }, "Should have panicked because of bad last config metadata")
   130  }
   131  
   132  // This test checks to make sure the orderer refuses to come up if it cannot find a system channel
   133  func TestNoSystemChain(t *testing.T) {
   134  	lf := ramledger.New(10)
   135  
   136  	consenters := make(map[string]Consenter)
   137  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   138  
   139  	assert.Panics(t, func() { NewManagerImpl(lf, consenters, mockCrypto()) }, "Should have panicked when starting without a system chain")
   140  }
   141  
   142  // This test checks to make sure that the orderer refuses to come up if there are multiple system channels
   143  func TestMultiSystemChannel(t *testing.T) {
   144  	lf := ramledger.New(10)
   145  
   146  	for _, id := range []string{"foo", "bar"} {
   147  		rl, err := lf.GetOrCreate(id)
   148  		assert.NoError(t, err)
   149  
   150  		err = rl.Append(provisional.New(conf).GenesisBlockForChannel(id))
   151  		assert.NoError(t, err)
   152  	}
   153  
   154  	consenters := make(map[string]Consenter)
   155  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   156  
   157  	assert.Panics(t, func() { NewManagerImpl(lf, consenters, mockCrypto()) }, "Two system channels should have caused panic")
   158  }
   159  
   160  // This test checks to make sure that the orderer creates different type of filters given different type of channel
   161  func TestFilterCreation(t *testing.T) {
   162  	lf := ramledger.New(10)
   163  	rl, err := lf.GetOrCreate(provisional.TestChainID)
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  	err = rl.Append(genesisBlock)
   168  	if err != nil {
   169  		panic(err)
   170  	}
   171  
   172  	// Creating a non-system chain to test that NewManagerImpl could handle the diversity
   173  	rl, err = lf.GetOrCreate(NoConsortiumChain)
   174  	if err != nil {
   175  		panic(err)
   176  	}
   177  	err = rl.Append(noConsortiumGenesisBlock)
   178  	if err != nil {
   179  		panic(err)
   180  	}
   181  
   182  	consenters := make(map[string]Consenter)
   183  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   184  
   185  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   186  
   187  	_, ok := manager.GetChain(provisional.TestChainID)
   188  	assert.True(t, ok, "Should have found chain: %d", provisional.TestChainID)
   189  
   190  	chainSupport, ok := manager.GetChain(NoConsortiumChain)
   191  	assert.True(t, ok, "Should have retrieved chain: %d", NoConsortiumChain)
   192  
   193  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   194  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   195  		messages[i] = &cb.Envelope{
   196  			Payload: utils.MarshalOrPanic(&cb.Payload{
   197  				Header: &cb.Header{
   198  					ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
   199  						// For testing purpose, we are injecting configTx into non-system channel.
   200  						// Set Type to HeaderType_ORDERER_TRANSACTION to verify this message is NOT
   201  						// filtered by SystemChainFilter, so we know we are creating correct type
   202  						// of filter for the chain.
   203  						Type:      int32(cb.HeaderType_ORDERER_TRANSACTION),
   204  						ChannelId: NoConsortiumChain,
   205  					}),
   206  					SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{}),
   207  				},
   208  				Data: []byte(fmt.Sprintf("%d", i)),
   209  			}),
   210  		}
   211  
   212  		assert.True(t, chainSupport.Enqueue(messages[i]), "Should have successfully enqueued message")
   213  	}
   214  
   215  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   216  	select {
   217  	case <-it.ReadyChan():
   218  		block, status := it.Next()
   219  		assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block")
   220  		for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   221  			assert.Equal(t, messages[i], utils.ExtractEnvelopeOrPanic(block, i), "Block contents wrong at index %d", i)
   222  		}
   223  	case <-time.After(time.Second):
   224  		t.Fatalf("Block 1 not produced after timeout")
   225  	}
   226  }
   227  
   228  // This test essentially brings the entire system up and is ultimately what main.go will replicate
   229  func TestManagerImpl(t *testing.T) {
   230  	lf, rl := NewRAMLedgerAndFactory(10)
   231  
   232  	consenters := make(map[string]Consenter)
   233  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   234  
   235  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   236  
   237  	_, ok := manager.GetChain("Fake")
   238  	assert.False(t, ok, "Should not have found a chain that was not created")
   239  
   240  	chainSupport, ok := manager.GetChain(provisional.TestChainID)
   241  	assert.True(t, ok, "Should have gotten chain which was initialized by ramledger")
   242  
   243  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   244  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   245  		messages[i] = makeNormalTx(provisional.TestChainID, i)
   246  	}
   247  
   248  	for _, message := range messages {
   249  		chainSupport.Enqueue(message)
   250  	}
   251  
   252  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   253  	select {
   254  	case <-it.ReadyChan():
   255  		block, status := it.Next()
   256  		assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block")
   257  		for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   258  			assert.Equal(t, messages[i], utils.ExtractEnvelopeOrPanic(block, i), "Block contents wrong at index %d", i)
   259  		}
   260  	case <-time.After(time.Second):
   261  		t.Fatalf("Block 1 not produced after timeout")
   262  	}
   263  }
   264  
   265  func TestNewChannelConfig(t *testing.T) {
   266  	lf, _ := NewRAMLedgerAndFactoryWithMSP()
   267  
   268  	consenters := make(map[string]Consenter)
   269  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   270  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   271  
   272  	t.Run("BadPayload", func(t *testing.T) {
   273  		_, err := manager.NewChannelConfig(&cb.Envelope{Payload: []byte("bad payload")})
   274  		assert.Error(t, err, "Should not be able to create new channel config from bad payload.")
   275  	})
   276  
   277  	for _, tc := range []struct {
   278  		name    string
   279  		payload *cb.Payload
   280  		regex   string
   281  	}{
   282  		{
   283  			"BadPayloadData",
   284  			&cb.Payload{
   285  				Data: []byte("bad payload data"),
   286  			},
   287  			"^Failing initial channel config creation because of config update envelope unmarshaling error:",
   288  		},
   289  		{
   290  			"BadConfigUpdate",
   291  			&cb.Payload{
   292  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   293  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   294  					ConfigUpdate: []byte("bad config update envelope data"),
   295  				}),
   296  			},
   297  			"^Failing initial channel config creation because of config update unmarshaling error:",
   298  		},
   299  		{
   300  			"EmptyConfigUpdateWriteSet",
   301  			&cb.Payload{
   302  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   303  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   304  					ConfigUpdate: utils.MarshalOrPanic(
   305  						&cb.ConfigUpdate{},
   306  					),
   307  				}),
   308  			},
   309  			"^Config update has an empty writeset$",
   310  		},
   311  		{
   312  			"WriteSetNoGroups",
   313  			&cb.Payload{
   314  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   315  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   316  					ConfigUpdate: utils.MarshalOrPanic(
   317  						&cb.ConfigUpdate{
   318  							WriteSet: &cb.ConfigGroup{},
   319  						},
   320  					),
   321  				}),
   322  			},
   323  			"^Config update has missing application group$",
   324  		},
   325  		{
   326  			"WriteSetNoApplicationGroup",
   327  			&cb.Payload{
   328  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   329  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   330  					ConfigUpdate: utils.MarshalOrPanic(
   331  						&cb.ConfigUpdate{
   332  							WriteSet: &cb.ConfigGroup{
   333  								Groups: map[string]*cb.ConfigGroup{},
   334  							},
   335  						},
   336  					),
   337  				}),
   338  			},
   339  			"^Config update has missing application group$",
   340  		},
   341  		{
   342  			"BadWriteSetApplicationGroupVersion",
   343  			&cb.Payload{
   344  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   345  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   346  					ConfigUpdate: utils.MarshalOrPanic(
   347  						&cb.ConfigUpdate{
   348  							WriteSet: &cb.ConfigGroup{
   349  								Groups: map[string]*cb.ConfigGroup{
   350  									config.ApplicationGroupKey: &cb.ConfigGroup{
   351  										Version: 100,
   352  									},
   353  								},
   354  							},
   355  						},
   356  					),
   357  				}),
   358  			},
   359  			"^Config update for channel creation does not set application group version to 1,",
   360  		},
   361  		{
   362  			"MissingWriteSetConsortiumValue",
   363  			&cb.Payload{
   364  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   365  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   366  					ConfigUpdate: utils.MarshalOrPanic(
   367  						&cb.ConfigUpdate{
   368  							WriteSet: &cb.ConfigGroup{
   369  								Groups: map[string]*cb.ConfigGroup{
   370  									config.ApplicationGroupKey: &cb.ConfigGroup{
   371  										Version: 1,
   372  									},
   373  								},
   374  								Values: map[string]*cb.ConfigValue{},
   375  							},
   376  						},
   377  					),
   378  				}),
   379  			},
   380  			"^Consortium config value missing$",
   381  		},
   382  		{
   383  			"BadWriteSetConsortiumValueValue",
   384  			&cb.Payload{
   385  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   386  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   387  					ConfigUpdate: utils.MarshalOrPanic(
   388  						&cb.ConfigUpdate{
   389  							WriteSet: &cb.ConfigGroup{
   390  								Groups: map[string]*cb.ConfigGroup{
   391  									config.ApplicationGroupKey: &cb.ConfigGroup{
   392  										Version: 1,
   393  									},
   394  								},
   395  								Values: map[string]*cb.ConfigValue{
   396  									config.ConsortiumKey: &cb.ConfigValue{
   397  										Value: []byte("bad consortium value"),
   398  									},
   399  								},
   400  							},
   401  						},
   402  					),
   403  				}),
   404  			},
   405  			"^Error reading unmarshaling consortium name:",
   406  		},
   407  		{
   408  			"UnknownConsortiumName",
   409  			&cb.Payload{
   410  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   411  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   412  					ConfigUpdate: utils.MarshalOrPanic(
   413  						&cb.ConfigUpdate{
   414  							WriteSet: &cb.ConfigGroup{
   415  								Groups: map[string]*cb.ConfigGroup{
   416  									config.ApplicationGroupKey: &cb.ConfigGroup{
   417  										Version: 1,
   418  									},
   419  								},
   420  								Values: map[string]*cb.ConfigValue{
   421  									config.ConsortiumKey: &cb.ConfigValue{
   422  										Value: utils.MarshalOrPanic(
   423  											&cb.Consortium{
   424  												Name: "NotTheNameYouAreLookingFor",
   425  											},
   426  										),
   427  									},
   428  								},
   429  							},
   430  						},
   431  					),
   432  				}),
   433  			},
   434  			"^Unknown consortium name:",
   435  		},
   436  		{
   437  			"Missing consortium members",
   438  			&cb.Payload{
   439  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   440  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   441  					ConfigUpdate: utils.MarshalOrPanic(
   442  						&cb.ConfigUpdate{
   443  							WriteSet: &cb.ConfigGroup{
   444  								Groups: map[string]*cb.ConfigGroup{
   445  									config.ApplicationGroupKey: &cb.ConfigGroup{
   446  										Version: 1,
   447  									},
   448  								},
   449  								Values: map[string]*cb.ConfigValue{
   450  									config.ConsortiumKey: &cb.ConfigValue{
   451  										Value: utils.MarshalOrPanic(
   452  											&cb.Consortium{
   453  												Name: genesisconfig.SampleConsortiumName,
   454  											},
   455  										),
   456  									},
   457  								},
   458  							},
   459  						},
   460  					),
   461  				}),
   462  			},
   463  			"Proposed configuration has no application group members, but consortium contains members",
   464  		},
   465  		{
   466  			"Member not in consortium",
   467  			&cb.Payload{
   468  				Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
   469  				Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   470  					ConfigUpdate: utils.MarshalOrPanic(
   471  						&cb.ConfigUpdate{
   472  							WriteSet: &cb.ConfigGroup{
   473  								Groups: map[string]*cb.ConfigGroup{
   474  									config.ApplicationGroupKey: &cb.ConfigGroup{
   475  										Version: 1,
   476  										Groups: map[string]*cb.ConfigGroup{
   477  											"BadOrgName": &cb.ConfigGroup{},
   478  										},
   479  									},
   480  								},
   481  								Values: map[string]*cb.ConfigValue{
   482  									config.ConsortiumKey: &cb.ConfigValue{
   483  										Value: utils.MarshalOrPanic(
   484  											&cb.Consortium{
   485  												Name: genesisconfig.SampleConsortiumName,
   486  											},
   487  										),
   488  									},
   489  								},
   490  							},
   491  						},
   492  					),
   493  				}),
   494  			},
   495  			"Attempted to include a member which is not in the consortium",
   496  		},
   497  	} {
   498  		t.Run(tc.name, func(t *testing.T) {
   499  			_, err := manager.NewChannelConfig(&cb.Envelope{Payload: utils.MarshalOrPanic(tc.payload)})
   500  			if assert.Error(t, err) {
   501  				assert.Regexp(t, tc.regex, err.Error())
   502  			}
   503  		})
   504  	}
   505  	// SampleConsortium
   506  }
   507  
   508  func TestMismatchedChannelIDs(t *testing.T) {
   509  	innerChannelID := "foo"
   510  	outerChannelID := "bar"
   511  	template := configtx.NewChainCreationTemplate(genesisconfig.SampleConsortiumName, nil)
   512  	configUpdateEnvelope, err := template.Envelope(innerChannelID)
   513  	createTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, outerChannelID, nil, configUpdateEnvelope, msgVersion, epoch)
   514  	assert.NoError(t, err)
   515  
   516  	lf, _ := NewRAMLedgerAndFactory(10)
   517  
   518  	consenters := make(map[string]Consenter)
   519  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   520  
   521  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   522  
   523  	_, err = manager.NewChannelConfig(createTx)
   524  	assert.Error(t, err, "Mismatched channel IDs")
   525  	assert.Regexp(t, "mismatched channel IDs", err.Error())
   526  }
   527  
   528  // This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
   529  func TestNewChain(t *testing.T) {
   530  	expectedLastConfigBlockNumber := uint64(0)
   531  	expectedLastConfigSeq := uint64(1)
   532  	newChainID := "test-new-chain"
   533  
   534  	lf, rl := NewRAMLedgerAndFactory(10)
   535  
   536  	consenters := make(map[string]Consenter)
   537  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   538  
   539  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   540  
   541  	envConfigUpdate, err := configtx.MakeChainCreationTransaction(newChainID, genesisconfig.SampleConsortiumName, mockSigningIdentity)
   542  	assert.NoError(t, err, "Constructing chain creation tx")
   543  
   544  	cm, err := manager.NewChannelConfig(envConfigUpdate)
   545  	assert.NoError(t, err, "Constructing initial channel config")
   546  
   547  	configEnv, err := cm.ProposeConfigUpdate(envConfigUpdate)
   548  	assert.NoError(t, err, "Proposing initial update")
   549  	assert.Equal(t, expectedLastConfigSeq, configEnv.GetConfig().Sequence, "Sequence of config envelope for new channel should always be set to %d", expectedLastConfigSeq)
   550  
   551  	ingressTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch)
   552  	assert.NoError(t, err, "Creating ingresstx")
   553  
   554  	wrapped := wrapConfigTx(ingressTx)
   555  
   556  	chainSupport, ok := manager.GetChain(manager.SystemChannelID())
   557  	assert.True(t, ok, "Could not find system channel")
   558  
   559  	chainSupport.Enqueue(wrapped)
   560  
   561  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   562  	select {
   563  	case <-it.ReadyChan():
   564  		block, status := it.Next()
   565  		if status != cb.Status_SUCCESS {
   566  			t.Fatalf("Could not retrieve block")
   567  		}
   568  		if len(block.Data.Data) != 1 {
   569  			t.Fatalf("Should have had only one message in the orderer transaction block")
   570  		}
   571  
   572  		assert.Equal(t, wrapped, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Orderer config block contains wrong transaction")
   573  	case <-time.After(time.Second):
   574  		t.Fatalf("Block 1 not produced after timeout in system chain")
   575  	}
   576  
   577  	chainSupport, ok = manager.GetChain(newChainID)
   578  
   579  	if !ok {
   580  		t.Fatalf("Should have gotten new chain which was created")
   581  	}
   582  
   583  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   584  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   585  		messages[i] = makeNormalTx(newChainID, i)
   586  	}
   587  
   588  	for _, message := range messages {
   589  		chainSupport.Enqueue(message)
   590  	}
   591  
   592  	it, _ = chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}})
   593  	select {
   594  	case <-it.ReadyChan():
   595  		block, status := it.Next()
   596  		if status != cb.Status_SUCCESS {
   597  			t.Fatalf("Could not retrieve new chain genesis block")
   598  		}
   599  		testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber)
   600  		if len(block.Data.Data) != 1 {
   601  			t.Fatalf("Should have had only one message in the new genesis block")
   602  		}
   603  
   604  		assert.Equal(t, ingressTx, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Genesis block contains wrong transaction")
   605  	case <-time.After(time.Second):
   606  		t.Fatalf("Block 1 not produced after timeout in system chain")
   607  	}
   608  
   609  	select {
   610  	case <-it.ReadyChan():
   611  		block, status := it.Next()
   612  		if status != cb.Status_SUCCESS {
   613  			t.Fatalf("Could not retrieve block on new chain")
   614  		}
   615  		testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber)
   616  		for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   617  			if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) {
   618  				t.Errorf("Block contents wrong at index %d in new chain", i)
   619  			}
   620  		}
   621  	case <-time.After(time.Second):
   622  		t.Fatalf("Block 1 not produced after timeout on new chain")
   623  	}
   624  
   625  	testRestartedChainSupport(t, chainSupport, consenters, expectedLastConfigSeq)
   626  }
   627  
   628  func testRestartedChainSupport(t *testing.T, cs ChainSupport, consenters map[string]Consenter, expectedLastConfigSeq uint64) {
   629  	ccs, ok := cs.(*chainSupport)
   630  	assert.True(t, ok, "Casting error")
   631  	rcs := newChainSupport(ccs.filters, ccs.ledgerResources, consenters, mockCrypto())
   632  	assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq")
   633  }
   634  
   635  func testLastConfigBlockNumber(t *testing.T, block *cb.Block, expectedBlockNumber uint64) {
   636  	metadataItem := &cb.Metadata{}
   637  	err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG], metadataItem)
   638  	assert.NoError(t, err, "Block should carry LAST_CONFIG metadata item")
   639  	lastConfig := &cb.LastConfig{}
   640  	err = proto.Unmarshal(metadataItem.Value, lastConfig)
   641  	assert.NoError(t, err, "LAST_CONFIG metadata item should carry last config value")
   642  	assert.Equal(t, expectedBlockNumber, lastConfig.Index, "LAST_CONFIG value should point to last config block")
   643  }