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 }