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