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