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 }