github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/manager_test.go (about)

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