github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/orderer/common/multichannel/blockwriter_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  	cb "github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric-protos-go/orderer"
    16  	"github.com/hyperledger/fabric/bccsp"
    17  	"github.com/hyperledger/fabric/bccsp/sw"
    18  	"github.com/hyperledger/fabric/common/channelconfig"
    19  	newchannelconfig "github.com/hyperledger/fabric/common/channelconfig"
    20  	"github.com/hyperledger/fabric/common/configtx"
    21  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    22  	"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger"
    23  	"github.com/hyperledger/fabric/common/metrics/disabled"
    24  	"github.com/hyperledger/fabric/core/config/configtest"
    25  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    26  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    27  	"github.com/hyperledger/fabric/internal/pkg/identity"
    28  	"github.com/hyperledger/fabric/orderer/common/blockcutter/mock"
    29  	"github.com/hyperledger/fabric/orderer/common/multichannel/mocks"
    30  	"github.com/hyperledger/fabric/protoutil"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  //go:generate counterfeiter -o mocks/configtx_validator.go --fake-name ConfigTXValidator . configtxValidator
    36  
    37  type configtxValidator interface {
    38  	configtx.Validator
    39  }
    40  
    41  type mockBlockWriterSupport struct {
    42  	*mocks.ConfigTXValidator
    43  	identity.SignerSerializer
    44  	blockledger.ReadWriter
    45  	fakeConfig *mock.OrdererConfig
    46  	bccsp      bccsp.BCCSP
    47  	sequence   uint64
    48  }
    49  
    50  func (mbws mockBlockWriterSupport) Update(bundle *newchannelconfig.Bundle) {
    51  	return
    52  }
    53  
    54  func (mbws mockBlockWriterSupport) CreateBundle(channelID string, config *cb.Config) (*newchannelconfig.Bundle, error) {
    55  	return channelconfig.NewBundle(channelID, config, mbws.bccsp)
    56  }
    57  
    58  func (mbws mockBlockWriterSupport) SharedConfig() newchannelconfig.Orderer {
    59  	return mbws.fakeConfig
    60  }
    61  
    62  func TestCreateBlock(t *testing.T) {
    63  	seedBlock := protoutil.NewBlock(7, []byte("lasthash"))
    64  	seedBlock.Data.Data = [][]byte{[]byte("somebytes")}
    65  
    66  	bw := &BlockWriter{lastBlock: seedBlock}
    67  	block := bw.CreateNextBlock([]*cb.Envelope{
    68  		{Payload: []byte("some other bytes")},
    69  	})
    70  
    71  	assert.Equal(t, seedBlock.Header.Number+1, block.Header.Number)
    72  	assert.Equal(t, protoutil.BlockDataHash(block.Data), block.Header.DataHash)
    73  	assert.Equal(t, protoutil.BlockHeaderHash(seedBlock.Header), block.Header.PreviousHash)
    74  }
    75  
    76  func TestBlockSignature(t *testing.T) {
    77  	dir, err := ioutil.TempDir("", "file-ledger")
    78  	require.NoError(t, err)
    79  	defer os.RemoveAll(dir)
    80  
    81  	rlf, err := fileledger.New(dir, &disabled.Provider{})
    82  	require.NoError(t, err)
    83  
    84  	l, err := rlf.GetOrCreate("mychannel")
    85  	assert.NoError(t, err)
    86  	lastBlock := protoutil.NewBlock(0, nil)
    87  	l.Append(lastBlock)
    88  
    89  	bw := &BlockWriter{
    90  		lastConfigBlockNum: 42,
    91  		support: &mockBlockWriterSupport{
    92  			SignerSerializer:  mockCrypto(),
    93  			ConfigTXValidator: &mocks.ConfigTXValidator{},
    94  			ReadWriter:        l,
    95  		},
    96  		lastBlock: protoutil.NewBlock(1, protoutil.BlockHeaderHash(lastBlock.Header)),
    97  	}
    98  
    99  	consensusMetadata := []byte("bar")
   100  	bw.commitBlock(consensusMetadata)
   101  
   102  	it, seq := l.Iterator(&orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{}})
   103  	assert.Equal(t, uint64(1), seq)
   104  	committedBlock, status := it.Next()
   105  	assert.Equal(t, cb.Status_SUCCESS, status)
   106  
   107  	md := protoutil.GetMetadataFromBlockOrPanic(committedBlock, cb.BlockMetadataIndex_SIGNATURES)
   108  
   109  	expectedMetadataValue := protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{
   110  		LastConfig:        &cb.LastConfig{Index: 42},
   111  		ConsenterMetadata: protoutil.MarshalOrPanic(&cb.Metadata{Value: consensusMetadata}),
   112  	})
   113  
   114  	assert.Equal(t, expectedMetadataValue, md.Value, "Value contains the consensus metadata and the last config")
   115  	assert.NotNil(t, md.Signatures, "Should have signature")
   116  }
   117  
   118  func TestBlockLastConfig(t *testing.T) {
   119  	lastConfigSeq := uint64(6)
   120  	newConfigSeq := lastConfigSeq + 1
   121  	newBlockNum := uint64(9)
   122  
   123  	mockValidator := &mocks.ConfigTXValidator{}
   124  	mockValidator.SequenceReturns(newConfigSeq)
   125  	bw := &BlockWriter{
   126  		support: &mockBlockWriterSupport{
   127  			SignerSerializer:  mockCrypto(),
   128  			ConfigTXValidator: mockValidator,
   129  		},
   130  		lastConfigSeq: lastConfigSeq,
   131  	}
   132  
   133  	block := protoutil.NewBlock(newBlockNum, []byte("foo"))
   134  	bw.addLastConfig(block)
   135  
   136  	assert.Equal(t, newBlockNum, bw.lastConfigBlockNum)
   137  	assert.Equal(t, newConfigSeq, bw.lastConfigSeq)
   138  
   139  	md := protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_LAST_CONFIG)
   140  	assert.NotNil(t, md.Value, "Value not be empty in this case")
   141  	assert.Nil(t, md.Signatures, "Should not have signature")
   142  
   143  	lc := protoutil.GetLastConfigIndexFromBlockOrPanic(block)
   144  	assert.Equal(t, newBlockNum, lc)
   145  }
   146  
   147  func TestWriteConfigBlock(t *testing.T) {
   148  	// TODO, use assert.PanicsWithValue once available
   149  	t.Run("EmptyBlock", func(t *testing.T) {
   150  		assert.Panics(t, func() { (&BlockWriter{}).WriteConfigBlock(&cb.Block{}, nil) })
   151  	})
   152  	t.Run("BadPayload", func(t *testing.T) {
   153  		assert.Panics(t, func() {
   154  			(&BlockWriter{}).WriteConfigBlock(&cb.Block{
   155  				Data: &cb.BlockData{
   156  					Data: [][]byte{
   157  						protoutil.MarshalOrPanic(&cb.Envelope{Payload: []byte("bad")}),
   158  					},
   159  				},
   160  			}, nil)
   161  		})
   162  	})
   163  	t.Run("MissingHeader", func(t *testing.T) {
   164  		assert.Panics(t, func() {
   165  			(&BlockWriter{}).WriteConfigBlock(&cb.Block{
   166  				Data: &cb.BlockData{
   167  					Data: [][]byte{
   168  						protoutil.MarshalOrPanic(&cb.Envelope{
   169  							Payload: protoutil.MarshalOrPanic(&cb.Payload{}),
   170  						}),
   171  					},
   172  				},
   173  			}, nil)
   174  		})
   175  	})
   176  	t.Run("BadChannelHeader", func(t *testing.T) {
   177  		assert.Panics(t, func() {
   178  			(&BlockWriter{}).WriteConfigBlock(&cb.Block{
   179  				Data: &cb.BlockData{
   180  					Data: [][]byte{
   181  						protoutil.MarshalOrPanic(&cb.Envelope{
   182  							Payload: protoutil.MarshalOrPanic(&cb.Payload{
   183  								Header: &cb.Header{
   184  									ChannelHeader: []byte("bad"),
   185  								},
   186  							}),
   187  						}),
   188  					},
   189  				},
   190  			}, nil)
   191  		})
   192  	})
   193  	t.Run("BadChannelHeaderType", func(t *testing.T) {
   194  		assert.Panics(t, func() {
   195  			(&BlockWriter{}).WriteConfigBlock(&cb.Block{
   196  				Data: &cb.BlockData{
   197  					Data: [][]byte{
   198  						protoutil.MarshalOrPanic(&cb.Envelope{
   199  							Payload: protoutil.MarshalOrPanic(&cb.Payload{
   200  								Header: &cb.Header{
   201  									ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{}),
   202  								},
   203  							}),
   204  						}),
   205  					},
   206  				},
   207  			}, nil)
   208  		})
   209  	})
   210  }
   211  
   212  func TestGoodWriteConfig(t *testing.T) {
   213  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   214  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   215  
   216  	tmpdir, err := ioutil.TempDir("", "file-ledger")
   217  	require.NoError(t, err)
   218  	defer os.RemoveAll(tmpdir)
   219  
   220  	_, l := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   221  
   222  	fakeConfig := &mock.OrdererConfig{}
   223  	fakeConfig.ConsensusTypeReturns("solo")
   224  
   225  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   226  	assert.NoError(t, err)
   227  
   228  	mockValidator := &mocks.ConfigTXValidator{}
   229  	mockValidator.ChannelIDReturns("testchannelid")
   230  	bw := newBlockWriter(genesisBlockSys, nil,
   231  		&mockBlockWriterSupport{
   232  			SignerSerializer:  mockCrypto(),
   233  			ReadWriter:        l,
   234  			ConfigTXValidator: mockValidator,
   235  			fakeConfig:        fakeConfig,
   236  			bccsp:             cryptoProvider,
   237  		},
   238  	)
   239  
   240  	ctx := makeConfigTxFull("testchannelid", 1)
   241  	block := protoutil.NewBlock(1, protoutil.BlockHeaderHash(genesisBlockSys.Header))
   242  	block.Data.Data = [][]byte{protoutil.MarshalOrPanic(ctx)}
   243  	consenterMetadata := []byte("foo")
   244  	bw.WriteConfigBlock(block, consenterMetadata)
   245  
   246  	// Wait for the commit to complete
   247  	bw.committingBlock.Lock()
   248  	bw.committingBlock.Unlock()
   249  
   250  	cBlock := blockledger.GetBlock(l, block.Header.Number)
   251  	assert.Equal(t, block.Header, cBlock.Header)
   252  	assert.Equal(t, block.Data, cBlock.Data)
   253  
   254  	omd, err := protoutil.GetConsenterMetadataFromBlock(block)
   255  	require.NoError(t, err)
   256  	assert.Equal(t, consenterMetadata, omd.Value)
   257  }
   258  
   259  func TestMigrationWriteConfig(t *testing.T) {
   260  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   261  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   262  
   263  	tmpdir, err := ioutil.TempDir("", "file-ledger")
   264  	require.NoError(t, err)
   265  	defer os.RemoveAll(tmpdir)
   266  
   267  	_, l := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   268  
   269  	fakeConfig := &mock.OrdererConfig{}
   270  	fakeConfig.ConsensusTypeReturns("solo")
   271  	fakeConfig.ConsensusStateReturns(orderer.ConsensusType_STATE_MAINTENANCE)
   272  
   273  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   274  	assert.NoError(t, err)
   275  
   276  	mockValidator := &mocks.ConfigTXValidator{}
   277  	mockValidator.ChannelIDReturns("testchannelid")
   278  	bw := newBlockWriter(genesisBlockSys, nil,
   279  		&mockBlockWriterSupport{
   280  			SignerSerializer:  mockCrypto(),
   281  			ReadWriter:        l,
   282  			ConfigTXValidator: mockValidator,
   283  			fakeConfig:        fakeConfig,
   284  			bccsp:             cryptoProvider,
   285  		},
   286  	)
   287  
   288  	ctx := makeConfigTxMig("testchannelid", 1)
   289  	block := protoutil.NewBlock(1, protoutil.BlockHeaderHash(genesisBlockSys.Header))
   290  	block.Data.Data = [][]byte{protoutil.MarshalOrPanic(ctx)}
   291  	consenterMetadata := []byte("foo")
   292  
   293  	bw.WriteConfigBlock(block, consenterMetadata)
   294  
   295  	// Wait for the commit to complete
   296  	bw.committingBlock.Lock()
   297  	bw.committingBlock.Unlock()
   298  
   299  	cBlock := blockledger.GetBlock(l, block.Header.Number)
   300  	assert.Equal(t, block.Header, cBlock.Header)
   301  	assert.Equal(t, block.Data, cBlock.Data)
   302  
   303  	omd := protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_ORDERER)
   304  	assert.Equal(t, []byte(nil), omd.Value)
   305  }
   306  
   307  func TestRaceWriteConfig(t *testing.T) {
   308  	confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   309  	genesisBlockSys := encoder.New(confSys).GenesisBlock()
   310  
   311  	tmpdir, err := ioutil.TempDir("", "file-ledger")
   312  	require.NoError(t, err)
   313  	defer os.RemoveAll(tmpdir)
   314  
   315  	_, l := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys)
   316  
   317  	fakeConfig := &mock.OrdererConfig{}
   318  	fakeConfig.ConsensusTypeReturns("solo")
   319  
   320  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   321  	assert.NoError(t, err)
   322  
   323  	mockValidator := &mocks.ConfigTXValidator{}
   324  	bw := newBlockWriter(genesisBlockSys, nil,
   325  		&mockBlockWriterSupport{
   326  			SignerSerializer:  mockCrypto(),
   327  			ReadWriter:        l,
   328  			ConfigTXValidator: mockValidator,
   329  			fakeConfig:        fakeConfig,
   330  			bccsp:             cryptoProvider,
   331  		},
   332  	)
   333  
   334  	ctx := makeConfigTxFull("testchannelid", 1)
   335  	block1 := protoutil.NewBlock(1, protoutil.BlockHeaderHash(genesisBlockSys.Header))
   336  	block1.Data.Data = [][]byte{protoutil.MarshalOrPanic(ctx)}
   337  	consenterMetadata1 := []byte("foo")
   338  	mockValidator.SequenceReturnsOnCall(1, 1)
   339  
   340  	ctx = makeConfigTxFull("testchannelid", 1)
   341  	block2 := protoutil.NewBlock(2, protoutil.BlockHeaderHash(block1.Header))
   342  	block2.Data.Data = [][]byte{protoutil.MarshalOrPanic(ctx)}
   343  	consenterMetadata2 := []byte("bar")
   344  	mockValidator.SequenceReturnsOnCall(2, 2)
   345  
   346  	bw.WriteConfigBlock(block1, consenterMetadata1)
   347  	bw.WriteConfigBlock(block2, consenterMetadata2)
   348  
   349  	// Wait for the commit to complete
   350  	bw.committingBlock.Lock()
   351  	bw.committingBlock.Unlock()
   352  
   353  	cBlock := blockledger.GetBlock(l, block1.Header.Number)
   354  	assert.Equal(t, block1.Header, cBlock.Header)
   355  	assert.Equal(t, block1.Data, cBlock.Data)
   356  	expectedLastConfigBlockNumber := block1.Header.Number
   357  	testLastConfigBlockNumber(t, block1, expectedLastConfigBlockNumber)
   358  
   359  	cBlock = blockledger.GetBlock(l, block2.Header.Number)
   360  	assert.Equal(t, block2.Header, cBlock.Header)
   361  	assert.Equal(t, block2.Data, cBlock.Data)
   362  	expectedLastConfigBlockNumber = block2.Header.Number
   363  	testLastConfigBlockNumber(t, block2, expectedLastConfigBlockNumber)
   364  
   365  	omd, err := protoutil.GetConsenterMetadataFromBlock(block1)
   366  	require.NoError(t, err)
   367  	assert.Equal(t, consenterMetadata1, omd.Value)
   368  }