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