github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/multichain/manager_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package multichain 8 9 import ( 10 "fmt" 11 "reflect" 12 "testing" 13 "time" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric/common/config" 17 "github.com/hyperledger/fabric/common/configtx" 18 genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig" 19 "github.com/hyperledger/fabric/common/configtx/tool/provisional" 20 mockcrypto "github.com/hyperledger/fabric/common/mocks/crypto" 21 "github.com/hyperledger/fabric/msp" 22 "github.com/hyperledger/fabric/orderer/ledger" 23 ramledger "github.com/hyperledger/fabric/orderer/ledger/ram" 24 cb "github.com/hyperledger/fabric/protos/common" 25 ab "github.com/hyperledger/fabric/protos/orderer" 26 "github.com/hyperledger/fabric/protos/utils" 27 28 mmsp "github.com/hyperledger/fabric/common/mocks/msp" 29 logging "github.com/op/go-logging" 30 "github.com/stretchr/testify/assert" 31 ) 32 33 var conf, singleMSPConf, noConsortiumConf *genesisconfig.Profile 34 var genesisBlock, singleMSPGenesisBlock, noConsortiumGenesisBlock *cb.Block 35 var mockSigningIdentity msp.SigningIdentity 36 37 const NoConsortiumChain = "no-consortium-chain" 38 39 func init() { 40 logging.SetLevel(logging.DEBUG, "") 41 mockSigningIdentity, _ = mmsp.NewNoopMsp().GetDefaultSigningIdentity() 42 43 conf = genesisconfig.Load(genesisconfig.SampleInsecureProfile) 44 genesisBlock = provisional.New(conf).GenesisBlock() 45 46 singleMSPConf = genesisconfig.Load(genesisconfig.SampleSingleMSPSoloProfile) 47 singleMSPGenesisBlock = provisional.New(singleMSPConf).GenesisBlock() 48 49 noConsortiumConf = genesisconfig.Load("SampleNoConsortium") 50 noConsortiumGenesisBlock = provisional.New(noConsortiumConf).GenesisBlockForChannel(NoConsortiumChain) 51 } 52 53 func mockCrypto() *mockCryptoHelper { 54 return &mockCryptoHelper{LocalSigner: mockcrypto.FakeLocalSigner} 55 } 56 57 type mockCryptoHelper struct { 58 *mockcrypto.LocalSigner 59 } 60 61 func (mch mockCryptoHelper) VerifySignature(sd *cb.SignedData) error { 62 return nil 63 } 64 65 func NewRAMLedgerAndFactory(maxSize int) (ledger.Factory, ledger.ReadWriter) { 66 rlf := ramledger.New(10) 67 rl, err := rlf.GetOrCreate(provisional.TestChainID) 68 if err != nil { 69 panic(err) 70 } 71 err = rl.Append(genesisBlock) 72 if err != nil { 73 panic(err) 74 } 75 return rlf, rl 76 } 77 78 func NewRAMLedgerAndFactoryWithMSP() (ledger.Factory, ledger.ReadWriter) { 79 rlf := ramledger.New(10) 80 81 rl, err := rlf.GetOrCreate(provisional.TestChainID) 82 if err != nil { 83 panic(err) 84 } 85 err = rl.Append(singleMSPGenesisBlock) 86 if err != nil { 87 panic(err) 88 } 89 return rlf, rl 90 } 91 92 func NewRAMLedger(maxSize int) ledger.ReadWriter { 93 _, rl := NewRAMLedgerAndFactory(maxSize) 94 return rl 95 } 96 97 // Tests for a normal chain which contains 3 config transactions and other normal transactions to make sure the right one returned 98 func TestGetConfigTx(t *testing.T) { 99 rl := NewRAMLedger(10) 100 for i := 0; i < 5; i++ { 101 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, i)})) 102 } 103 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)})) 104 ctx := makeConfigTx(provisional.TestChainID, 6) 105 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{ctx})) 106 107 block := ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)}) 108 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 7})}) 109 rl.Append(block) 110 111 pctx := getConfigTx(rl) 112 assert.Equal(t, pctx, ctx, "Did not select most recent config transaction") 113 } 114 115 // Tests a chain which contains blocks with multi-transactions mixed with config txs, and a single tx which is not a config tx, none count as config blocks so nil should return 116 func TestGetConfigTxFailure(t *testing.T) { 117 rl := NewRAMLedger(10) 118 for i := 0; i < 10; i++ { 119 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{ 120 makeNormalTx(provisional.TestChainID, i), 121 makeConfigTx(provisional.TestChainID, i), 122 })) 123 } 124 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)})) 125 assert.Panics(t, func() { getConfigTx(rl) }, "Should have panicked because there was no config tx") 126 127 block := ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 12)}) 128 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = []byte("bad metadata") 129 assert.Panics(t, func() { getConfigTx(rl) }, "Should have panicked because of bad last config metadata") 130 } 131 132 // This test checks to make sure the orderer refuses to come up if it cannot find a system channel 133 func TestNoSystemChain(t *testing.T) { 134 lf := ramledger.New(10) 135 136 consenters := make(map[string]Consenter) 137 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 138 139 assert.Panics(t, func() { NewManagerImpl(lf, consenters, mockCrypto()) }, "Should have panicked when starting without a system chain") 140 } 141 142 // This test checks to make sure that the orderer refuses to come up if there are multiple system channels 143 func TestMultiSystemChannel(t *testing.T) { 144 lf := ramledger.New(10) 145 146 for _, id := range []string{"foo", "bar"} { 147 rl, err := lf.GetOrCreate(id) 148 assert.NoError(t, err) 149 150 err = rl.Append(provisional.New(conf).GenesisBlockForChannel(id)) 151 assert.NoError(t, err) 152 } 153 154 consenters := make(map[string]Consenter) 155 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 156 157 assert.Panics(t, func() { NewManagerImpl(lf, consenters, mockCrypto()) }, "Two system channels should have caused panic") 158 } 159 160 // This test checks to make sure that the orderer creates different type of filters given different type of channel 161 func TestFilterCreation(t *testing.T) { 162 lf := ramledger.New(10) 163 rl, err := lf.GetOrCreate(provisional.TestChainID) 164 if err != nil { 165 panic(err) 166 } 167 err = rl.Append(genesisBlock) 168 if err != nil { 169 panic(err) 170 } 171 172 // Creating a non-system chain to test that NewManagerImpl could handle the diversity 173 rl, err = lf.GetOrCreate(NoConsortiumChain) 174 if err != nil { 175 panic(err) 176 } 177 err = rl.Append(noConsortiumGenesisBlock) 178 if err != nil { 179 panic(err) 180 } 181 182 consenters := make(map[string]Consenter) 183 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 184 185 manager := NewManagerImpl(lf, consenters, mockCrypto()) 186 187 _, ok := manager.GetChain(provisional.TestChainID) 188 assert.True(t, ok, "Should have found chain: %d", provisional.TestChainID) 189 190 chainSupport, ok := manager.GetChain(NoConsortiumChain) 191 assert.True(t, ok, "Should have retrieved chain: %d", NoConsortiumChain) 192 193 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 194 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 195 messages[i] = &cb.Envelope{ 196 Payload: utils.MarshalOrPanic(&cb.Payload{ 197 Header: &cb.Header{ 198 ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ 199 // For testing purpose, we are injecting configTx into non-system channel. 200 // Set Type to HeaderType_ORDERER_TRANSACTION to verify this message is NOT 201 // filtered by SystemChainFilter, so we know we are creating correct type 202 // of filter for the chain. 203 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 204 ChannelId: NoConsortiumChain, 205 }), 206 SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{}), 207 }, 208 Data: []byte(fmt.Sprintf("%d", i)), 209 }), 210 } 211 212 assert.True(t, chainSupport.Enqueue(messages[i]), "Should have successfully enqueued message") 213 } 214 215 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 216 select { 217 case <-it.ReadyChan(): 218 block, status := it.Next() 219 assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block") 220 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 221 assert.Equal(t, messages[i], utils.ExtractEnvelopeOrPanic(block, i), "Block contents wrong at index %d", i) 222 } 223 case <-time.After(time.Second): 224 t.Fatalf("Block 1 not produced after timeout") 225 } 226 } 227 228 // This test essentially brings the entire system up and is ultimately what main.go will replicate 229 func TestManagerImpl(t *testing.T) { 230 lf, rl := NewRAMLedgerAndFactory(10) 231 232 consenters := make(map[string]Consenter) 233 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 234 235 manager := NewManagerImpl(lf, consenters, mockCrypto()) 236 237 _, ok := manager.GetChain("Fake") 238 assert.False(t, ok, "Should not have found a chain that was not created") 239 240 chainSupport, ok := manager.GetChain(provisional.TestChainID) 241 assert.True(t, ok, "Should have gotten chain which was initialized by ramledger") 242 243 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 244 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 245 messages[i] = makeNormalTx(provisional.TestChainID, i) 246 } 247 248 for _, message := range messages { 249 chainSupport.Enqueue(message) 250 } 251 252 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 253 select { 254 case <-it.ReadyChan(): 255 block, status := it.Next() 256 assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block") 257 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 258 assert.Equal(t, messages[i], utils.ExtractEnvelopeOrPanic(block, i), "Block contents wrong at index %d", i) 259 } 260 case <-time.After(time.Second): 261 t.Fatalf("Block 1 not produced after timeout") 262 } 263 } 264 265 func TestNewChannelConfig(t *testing.T) { 266 lf, _ := NewRAMLedgerAndFactoryWithMSP() 267 268 consenters := make(map[string]Consenter) 269 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 270 manager := NewManagerImpl(lf, consenters, mockCrypto()) 271 272 t.Run("BadPayload", func(t *testing.T) { 273 _, err := manager.NewChannelConfig(&cb.Envelope{Payload: []byte("bad payload")}) 274 assert.Error(t, err, "Should not be able to create new channel config from bad payload.") 275 }) 276 277 for _, tc := range []struct { 278 name string 279 payload *cb.Payload 280 regex string 281 }{ 282 { 283 "BadPayloadData", 284 &cb.Payload{ 285 Data: []byte("bad payload data"), 286 }, 287 "^Failing initial channel config creation because of config update envelope unmarshaling error:", 288 }, 289 { 290 "BadConfigUpdate", 291 &cb.Payload{ 292 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 293 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 294 ConfigUpdate: []byte("bad config update envelope data"), 295 }), 296 }, 297 "^Failing initial channel config creation because of config update unmarshaling error:", 298 }, 299 { 300 "EmptyConfigUpdateWriteSet", 301 &cb.Payload{ 302 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 303 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 304 ConfigUpdate: utils.MarshalOrPanic( 305 &cb.ConfigUpdate{}, 306 ), 307 }), 308 }, 309 "^Config update has an empty writeset$", 310 }, 311 { 312 "WriteSetNoGroups", 313 &cb.Payload{ 314 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 315 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 316 ConfigUpdate: utils.MarshalOrPanic( 317 &cb.ConfigUpdate{ 318 WriteSet: &cb.ConfigGroup{}, 319 }, 320 ), 321 }), 322 }, 323 "^Config update has missing application group$", 324 }, 325 { 326 "WriteSetNoApplicationGroup", 327 &cb.Payload{ 328 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 329 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 330 ConfigUpdate: utils.MarshalOrPanic( 331 &cb.ConfigUpdate{ 332 WriteSet: &cb.ConfigGroup{ 333 Groups: map[string]*cb.ConfigGroup{}, 334 }, 335 }, 336 ), 337 }), 338 }, 339 "^Config update has missing application group$", 340 }, 341 { 342 "BadWriteSetApplicationGroupVersion", 343 &cb.Payload{ 344 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 345 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 346 ConfigUpdate: utils.MarshalOrPanic( 347 &cb.ConfigUpdate{ 348 WriteSet: &cb.ConfigGroup{ 349 Groups: map[string]*cb.ConfigGroup{ 350 config.ApplicationGroupKey: &cb.ConfigGroup{ 351 Version: 100, 352 }, 353 }, 354 }, 355 }, 356 ), 357 }), 358 }, 359 "^Config update for channel creation does not set application group version to 1,", 360 }, 361 { 362 "MissingWriteSetConsortiumValue", 363 &cb.Payload{ 364 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 365 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 366 ConfigUpdate: utils.MarshalOrPanic( 367 &cb.ConfigUpdate{ 368 WriteSet: &cb.ConfigGroup{ 369 Groups: map[string]*cb.ConfigGroup{ 370 config.ApplicationGroupKey: &cb.ConfigGroup{ 371 Version: 1, 372 }, 373 }, 374 Values: map[string]*cb.ConfigValue{}, 375 }, 376 }, 377 ), 378 }), 379 }, 380 "^Consortium config value missing$", 381 }, 382 { 383 "BadWriteSetConsortiumValueValue", 384 &cb.Payload{ 385 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 386 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 387 ConfigUpdate: utils.MarshalOrPanic( 388 &cb.ConfigUpdate{ 389 WriteSet: &cb.ConfigGroup{ 390 Groups: map[string]*cb.ConfigGroup{ 391 config.ApplicationGroupKey: &cb.ConfigGroup{ 392 Version: 1, 393 }, 394 }, 395 Values: map[string]*cb.ConfigValue{ 396 config.ConsortiumKey: &cb.ConfigValue{ 397 Value: []byte("bad consortium value"), 398 }, 399 }, 400 }, 401 }, 402 ), 403 }), 404 }, 405 "^Error reading unmarshaling consortium name:", 406 }, 407 { 408 "UnknownConsortiumName", 409 &cb.Payload{ 410 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 411 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 412 ConfigUpdate: utils.MarshalOrPanic( 413 &cb.ConfigUpdate{ 414 WriteSet: &cb.ConfigGroup{ 415 Groups: map[string]*cb.ConfigGroup{ 416 config.ApplicationGroupKey: &cb.ConfigGroup{ 417 Version: 1, 418 }, 419 }, 420 Values: map[string]*cb.ConfigValue{ 421 config.ConsortiumKey: &cb.ConfigValue{ 422 Value: utils.MarshalOrPanic( 423 &cb.Consortium{ 424 Name: "NotTheNameYouAreLookingFor", 425 }, 426 ), 427 }, 428 }, 429 }, 430 }, 431 ), 432 }), 433 }, 434 "^Unknown consortium name:", 435 }, 436 { 437 "Missing consortium members", 438 &cb.Payload{ 439 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 440 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 441 ConfigUpdate: utils.MarshalOrPanic( 442 &cb.ConfigUpdate{ 443 WriteSet: &cb.ConfigGroup{ 444 Groups: map[string]*cb.ConfigGroup{ 445 config.ApplicationGroupKey: &cb.ConfigGroup{ 446 Version: 1, 447 }, 448 }, 449 Values: map[string]*cb.ConfigValue{ 450 config.ConsortiumKey: &cb.ConfigValue{ 451 Value: utils.MarshalOrPanic( 452 &cb.Consortium{ 453 Name: genesisconfig.SampleConsortiumName, 454 }, 455 ), 456 }, 457 }, 458 }, 459 }, 460 ), 461 }), 462 }, 463 "Proposed configuration has no application group members, but consortium contains members", 464 }, 465 { 466 "Member not in consortium", 467 &cb.Payload{ 468 Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))}, 469 Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{ 470 ConfigUpdate: utils.MarshalOrPanic( 471 &cb.ConfigUpdate{ 472 WriteSet: &cb.ConfigGroup{ 473 Groups: map[string]*cb.ConfigGroup{ 474 config.ApplicationGroupKey: &cb.ConfigGroup{ 475 Version: 1, 476 Groups: map[string]*cb.ConfigGroup{ 477 "BadOrgName": &cb.ConfigGroup{}, 478 }, 479 }, 480 }, 481 Values: map[string]*cb.ConfigValue{ 482 config.ConsortiumKey: &cb.ConfigValue{ 483 Value: utils.MarshalOrPanic( 484 &cb.Consortium{ 485 Name: genesisconfig.SampleConsortiumName, 486 }, 487 ), 488 }, 489 }, 490 }, 491 }, 492 ), 493 }), 494 }, 495 "Attempted to include a member which is not in the consortium", 496 }, 497 } { 498 t.Run(tc.name, func(t *testing.T) { 499 _, err := manager.NewChannelConfig(&cb.Envelope{Payload: utils.MarshalOrPanic(tc.payload)}) 500 if assert.Error(t, err) { 501 assert.Regexp(t, tc.regex, err.Error()) 502 } 503 }) 504 } 505 // SampleConsortium 506 } 507 508 func TestMismatchedChannelIDs(t *testing.T) { 509 innerChannelID := "foo" 510 outerChannelID := "bar" 511 template := configtx.NewChainCreationTemplate(genesisconfig.SampleConsortiumName, nil) 512 configUpdateEnvelope, err := template.Envelope(innerChannelID) 513 createTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, outerChannelID, nil, configUpdateEnvelope, msgVersion, epoch) 514 assert.NoError(t, err) 515 516 lf, _ := NewRAMLedgerAndFactory(10) 517 518 consenters := make(map[string]Consenter) 519 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 520 521 manager := NewManagerImpl(lf, consenters, mockCrypto()) 522 523 _, err = manager.NewChannelConfig(createTx) 524 assert.Error(t, err, "Mismatched channel IDs") 525 assert.Regexp(t, "mismatched channel IDs", err.Error()) 526 } 527 528 // This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain 529 func TestNewChain(t *testing.T) { 530 expectedLastConfigBlockNumber := uint64(0) 531 expectedLastConfigSeq := uint64(1) 532 newChainID := "test-new-chain" 533 534 lf, rl := NewRAMLedgerAndFactory(10) 535 536 consenters := make(map[string]Consenter) 537 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 538 539 manager := NewManagerImpl(lf, consenters, mockCrypto()) 540 541 envConfigUpdate, err := configtx.MakeChainCreationTransaction(newChainID, genesisconfig.SampleConsortiumName, mockSigningIdentity) 542 assert.NoError(t, err, "Constructing chain creation tx") 543 544 cm, err := manager.NewChannelConfig(envConfigUpdate) 545 assert.NoError(t, err, "Constructing initial channel config") 546 547 configEnv, err := cm.ProposeConfigUpdate(envConfigUpdate) 548 assert.NoError(t, err, "Proposing initial update") 549 assert.Equal(t, expectedLastConfigSeq, configEnv.GetConfig().Sequence, "Sequence of config envelope for new channel should always be set to %d", expectedLastConfigSeq) 550 551 ingressTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch) 552 assert.NoError(t, err, "Creating ingresstx") 553 554 wrapped := wrapConfigTx(ingressTx) 555 556 chainSupport, ok := manager.GetChain(manager.SystemChannelID()) 557 assert.True(t, ok, "Could not find system channel") 558 559 chainSupport.Enqueue(wrapped) 560 561 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 562 select { 563 case <-it.ReadyChan(): 564 block, status := it.Next() 565 if status != cb.Status_SUCCESS { 566 t.Fatalf("Could not retrieve block") 567 } 568 if len(block.Data.Data) != 1 { 569 t.Fatalf("Should have had only one message in the orderer transaction block") 570 } 571 572 assert.Equal(t, wrapped, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Orderer config block contains wrong transaction") 573 case <-time.After(time.Second): 574 t.Fatalf("Block 1 not produced after timeout in system chain") 575 } 576 577 chainSupport, ok = manager.GetChain(newChainID) 578 579 if !ok { 580 t.Fatalf("Should have gotten new chain which was created") 581 } 582 583 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 584 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 585 messages[i] = makeNormalTx(newChainID, i) 586 } 587 588 for _, message := range messages { 589 chainSupport.Enqueue(message) 590 } 591 592 it, _ = chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}}) 593 select { 594 case <-it.ReadyChan(): 595 block, status := it.Next() 596 if status != cb.Status_SUCCESS { 597 t.Fatalf("Could not retrieve new chain genesis block") 598 } 599 testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber) 600 if len(block.Data.Data) != 1 { 601 t.Fatalf("Should have had only one message in the new genesis block") 602 } 603 604 assert.Equal(t, ingressTx, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Genesis block contains wrong transaction") 605 case <-time.After(time.Second): 606 t.Fatalf("Block 1 not produced after timeout in system chain") 607 } 608 609 select { 610 case <-it.ReadyChan(): 611 block, status := it.Next() 612 if status != cb.Status_SUCCESS { 613 t.Fatalf("Could not retrieve block on new chain") 614 } 615 testLastConfigBlockNumber(t, block, expectedLastConfigBlockNumber) 616 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 617 if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) { 618 t.Errorf("Block contents wrong at index %d in new chain", i) 619 } 620 } 621 case <-time.After(time.Second): 622 t.Fatalf("Block 1 not produced after timeout on new chain") 623 } 624 625 testRestartedChainSupport(t, chainSupport, consenters, expectedLastConfigSeq) 626 } 627 628 func testRestartedChainSupport(t *testing.T, cs ChainSupport, consenters map[string]Consenter, expectedLastConfigSeq uint64) { 629 ccs, ok := cs.(*chainSupport) 630 assert.True(t, ok, "Casting error") 631 rcs := newChainSupport(ccs.filters, ccs.ledgerResources, consenters, mockCrypto()) 632 assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq") 633 } 634 635 func testLastConfigBlockNumber(t *testing.T, block *cb.Block, expectedBlockNumber uint64) { 636 metadataItem := &cb.Metadata{} 637 err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG], metadataItem) 638 assert.NoError(t, err, "Block should carry LAST_CONFIG metadata item") 639 lastConfig := &cb.LastConfig{} 640 err = proto.Unmarshal(metadataItem.Value, lastConfig) 641 assert.NoError(t, err, "LAST_CONFIG metadata item should carry last config value") 642 assert.Equal(t, expectedBlockNumber, lastConfig.Index, "LAST_CONFIG value should point to last config block") 643 }