github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/consensus/etcdraft/consenter_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package etcdraft_test 8 9 import ( 10 "encoding/pem" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path" 15 "path/filepath" 16 "strings" 17 "time" 18 19 "github.com/golang/protobuf/proto" 20 "github.com/hechain20/hechain/bccsp/sw" 21 "github.com/hechain20/hechain/common/channelconfig" 22 "github.com/hechain20/hechain/common/crypto/tlsgen" 23 "github.com/hechain20/hechain/common/flogging" 24 "github.com/hechain20/hechain/common/ledger/testutil" 25 "github.com/hechain20/hechain/core/config/configtest" 26 "github.com/hechain20/hechain/internal/configtxgen/encoder" 27 "github.com/hechain20/hechain/internal/configtxgen/genesisconfig" 28 "github.com/hechain20/hechain/internal/pkg/comm" 29 "github.com/hechain20/hechain/orderer/common/cluster" 30 clustermocks "github.com/hechain20/hechain/orderer/common/cluster/mocks" 31 "github.com/hechain20/hechain/orderer/common/types" 32 "github.com/hechain20/hechain/orderer/consensus" 33 "github.com/hechain20/hechain/orderer/consensus/etcdraft" 34 "github.com/hechain20/hechain/orderer/consensus/etcdraft/mocks" 35 "github.com/hechain20/hechain/orderer/consensus/inactive" 36 consensusmocks "github.com/hechain20/hechain/orderer/consensus/mocks" 37 "github.com/hechain20/hechain/protoutil" 38 "github.com/hyperledger/fabric-protos-go/common" 39 "github.com/hyperledger/fabric-protos-go/orderer" 40 etcdraftproto "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" 41 . "github.com/onsi/ginkgo" 42 . "github.com/onsi/ginkgo/extensions/table" 43 . "github.com/onsi/gomega" 44 gtypes "github.com/onsi/gomega/types" 45 "github.com/pkg/errors" 46 "github.com/stretchr/testify/mock" 47 "go.uber.org/zap" 48 "go.uber.org/zap/zapcore" 49 ) 50 51 var certAsPEM []byte 52 53 //go:generate counterfeiter -o mocks/orderer_capabilities.go --fake-name OrdererCapabilities . ordererCapabilities 54 type ordererCapabilities interface { 55 channelconfig.OrdererCapabilities 56 } 57 58 //go:generate counterfeiter -o mocks/orderer_config.go --fake-name OrdererConfig . ordererConfig 59 type ordererConfig interface { 60 channelconfig.Orderer 61 } 62 63 var _ = Describe("Consenter", func() { 64 var ( 65 chainManager *mocks.ChainManager 66 support *consensusmocks.FakeConsenterSupport 67 dataDir string 68 snapDir string 69 walDir string 70 tlsCA tlsgen.CA 71 ) 72 73 BeforeEach(func() { 74 var err error 75 tlsCA, err = tlsgen.NewCA() 76 Expect(err).NotTo(HaveOccurred()) 77 kp, err := tlsCA.NewClientCertKeyPair() 78 Expect(err).NotTo(HaveOccurred()) 79 if certAsPEM == nil { 80 certAsPEM = kp.Cert 81 } 82 chainManager = &mocks.ChainManager{} 83 support = &consensusmocks.FakeConsenterSupport{} 84 dataDir, err = ioutil.TempDir("", "consenter-") 85 Expect(err).NotTo(HaveOccurred()) 86 walDir = path.Join(dataDir, "wal-") 87 snapDir = path.Join(dataDir, "snap-") 88 89 blockBytes, err := ioutil.ReadFile("testdata/mychannel.block") 90 Expect(err).NotTo(HaveOccurred()) 91 92 goodConfigBlock := &common.Block{} 93 proto.Unmarshal(blockBytes, goodConfigBlock) 94 95 lastBlock := &common.Block{ 96 Header: &common.BlockHeader{ 97 Number: 1, 98 }, 99 Data: goodConfigBlock.Data, 100 Metadata: &common.BlockMetadata{ 101 Metadata: [][]byte{{}, protoutil.MarshalOrPanic(&common.Metadata{ 102 Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 0}), 103 })}, 104 }, 105 } 106 107 support.BlockReturns(lastBlock) 108 }) 109 110 AfterEach(func() { 111 if dataDir != "" { 112 os.RemoveAll(dataDir) 113 } 114 }) 115 116 When("the consenter is extracting the channel", func() { 117 It("extracts successfully from step requests", func() { 118 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 119 ch := consenter.TargetChannel(&orderer.ConsensusRequest{Channel: "mychannel"}) 120 Expect(ch).To(BeIdenticalTo("mychannel")) 121 }) 122 123 It("extracts successfully from submit requests", func() { 124 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 125 ch := consenter.TargetChannel(&orderer.SubmitRequest{Channel: "mychannel"}) 126 Expect(ch).To(BeIdenticalTo("mychannel")) 127 }) 128 129 It("returns an empty string for the rest of the messages", func() { 130 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 131 ch := consenter.TargetChannel(&common.Block{}) 132 Expect(ch).To(BeEmpty()) 133 }) 134 }) 135 136 DescribeTable("identifies a bad block", 137 func(block *common.Block, errMatcher gtypes.GomegaMatcher) { 138 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 139 isMem, err := consenter.IsChannelMember(block) 140 Expect(isMem).To(BeFalse()) 141 Expect(err).To(errMatcher) 142 }, 143 Entry("nil block", nil, MatchError("nil block")), 144 Entry("data is nil", &common.Block{}, MatchError("block data is nil")), 145 Entry("data is empty", protoutil.NewBlock(10, []byte{1, 2, 3, 4}), MatchError("envelope index out of bounds")), 146 Entry("bad data", 147 func() *common.Block { 148 block := protoutil.NewBlock(10, []byte{1, 2, 3, 4}) 149 block.Data.Data = [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}} 150 return block 151 }(), 152 MatchError(HavePrefix("block data does not carry an envelope at index 0: error unmarshalling Envelope: proto:"))), 153 ) 154 155 When("the consenter is asked about join-block membership", func() { 156 var ( 157 mspDir string 158 memberKeyPair *tlsgen.CertKeyPair 159 genesisBlockApp *common.Block 160 confAppRaft *genesisconfig.Profile 161 ) 162 163 BeforeEach(func() { 164 var err error 165 mspDir, err = ioutil.TempDir(dataDir, "msp") 166 Expect(err).NotTo(HaveOccurred()) 167 168 confAppRaft = genesisconfig.Load(genesisconfig.SampleDevModeEtcdRaftProfile, configtest.GetDevConfigDir()) 169 confAppRaft.Consortiums = nil 170 confAppRaft.Consortium = "" 171 172 // IsChannelMember verifies config meta along with it's tls certs 173 // ofconsenters. So when we add new conseter with tls certs, they must be 174 // signed by any msp from orderer config. Consenters in this test will 175 // have certificates from fixtures generated by tlsgen pkg. To pass 176 // validation, root ca cert should be part of a MSP in orderer config. 177 // Adding tls ca root cert to an existing ordering org's MSP definition. 178 Expect(confAppRaft.Orderer).NotTo(BeNil()) 179 Expect(confAppRaft.Orderer.Organizations).ToNot(HaveLen(0)) 180 Expect(confAppRaft.Orderer.EtcdRaft.Consenters).ToNot(HaveLen(0)) 181 182 // one consenter is enough for testing 183 confAppRaft.Orderer.EtcdRaft.Consenters = confAppRaft.Orderer.EtcdRaft.Consenters[:1] 184 185 // Generate client pair using tlsCA and set it to the consenter 186 memberKeyPair, err = tlsCA.NewServerCertKeyPair("127.0.0.1", "::1", "localhost") 187 Expect(err).NotTo(HaveOccurred()) 188 consenterDir, err := ioutil.TempDir(dataDir, "consenter") 189 Expect(err).NotTo(HaveOccurred()) 190 consenterCertPath := filepath.Join(consenterDir, "client.pem") 191 err = ioutil.WriteFile(consenterCertPath, memberKeyPair.Cert, 0o644) 192 Expect(err).NotTo(HaveOccurred()) 193 194 confAppRaft.Orderer.EtcdRaft.Consenters[0].ClientTlsCert = []byte(consenterCertPath) 195 confAppRaft.Orderer.EtcdRaft.Consenters[0].ServerTlsCert = []byte(consenterCertPath) 196 197 // Don't want to spoil sampleconfig, copying it to some tmp dir. 198 err = testutil.CopyDir(confAppRaft.Orderer.Organizations[0].MSPDir, mspDir, true) 199 Expect(err).NotTo(HaveOccurred()) 200 confAppRaft.Orderer.Organizations[0].MSPDir = mspDir 201 confAppRaft.Orderer.Organizations[0].ID = fmt.Sprintf("SampleMSP-%d", time.Now().UnixNano()) 202 203 // Write the TLS root cert to the msp folder 204 err = ioutil.WriteFile(filepath.Join(mspDir, "tlscacerts", "cert.pem"), tlsCA.CertBytes(), 0o644) 205 Expect(err).NotTo(HaveOccurred()) 206 207 bootstrapper, err := encoder.NewBootstrapper(confAppRaft) 208 Expect(err).NotTo(HaveOccurred()) 209 genesisBlockApp = bootstrapper.GenesisBlockForChannel("my-raft-channel") 210 Expect(genesisBlockApp).NotTo(BeNil()) 211 }) 212 213 It("identifies a member block", func() { 214 consenter := newConsenter(chainManager, tlsCA.CertBytes(), memberKeyPair.Cert) 215 isMem, err := consenter.IsChannelMember(genesisBlockApp) 216 Expect(isMem).To(BeTrue()) 217 Expect(err).NotTo(HaveOccurred()) 218 }) 219 220 It("identifies a non-member block", func() { 221 foreignCA, err := tlsgen.NewCA() 222 Expect(err).NotTo(HaveOccurred()) 223 nonMemberKeyPair, err := foreignCA.NewServerCertKeyPair("127.0.0.1", "::1", "localhost") 224 Expect(err).NotTo(HaveOccurred()) 225 226 consenter := newConsenter(chainManager, tlsCA.CertBytes(), nonMemberKeyPair.Cert) 227 isMem, err := consenter.IsChannelMember(genesisBlockApp) 228 Expect(isMem).To(BeFalse()) 229 Expect(err).NotTo(HaveOccurred()) 230 }) 231 232 It("raft config has consenter with certificate that is not signed by any msp", func() { 233 // This TLS root cert will not be part of the MSP. 234 foreignCA, err := tlsgen.NewCA() 235 Expect(err).NotTo(HaveOccurred()) 236 foreignKeyPair, err := foreignCA.NewServerCertKeyPair("127.0.0.1", "::1", "localhost") 237 Expect(err).NotTo(HaveOccurred()) 238 239 consenterDir, err := ioutil.TempDir(dataDir, "foreign-consenter") 240 Expect(err).NotTo(HaveOccurred()) 241 foreignConsenterCertPath := filepath.Join(consenterDir, "client.pem") 242 err = ioutil.WriteFile(foreignConsenterCertPath, foreignKeyPair.Cert, 0o644) 243 Expect(err).NotTo(HaveOccurred()) 244 245 confAppRaft.Orderer.EtcdRaft.Consenters[0].ClientTlsCert = []byte(foreignConsenterCertPath) 246 confAppRaft.Orderer.EtcdRaft.Consenters[0].ServerTlsCert = []byte(foreignConsenterCertPath) 247 248 consenter := newConsenter(chainManager, foreignCA.CertBytes(), foreignKeyPair.Cert) 249 250 bootstrapper, err := encoder.NewBootstrapper(confAppRaft) 251 Expect(err).NotTo(HaveOccurred()) 252 genesisBlockApp = bootstrapper.GenesisBlockForChannel("my-raft-channel") 253 Expect(genesisBlockApp).NotTo(BeNil()) 254 255 isMem, err := consenter.IsChannelMember(genesisBlockApp) 256 Expect(isMem).To(BeFalse()) 257 Expect(err).To(HaveOccurred()) 258 }) 259 }) 260 261 When("the consenter is asked for a chain", func() { 262 cryptoProvider, _ := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 263 chainInstance := &etcdraft.Chain{CryptoProvider: cryptoProvider} 264 BeforeEach(func() { 265 chainManager.GetConsensusChainStub = func(channel string) consensus.Chain { 266 switch channel { 267 case "mychannel": 268 return chainInstance 269 case "notraftchain": 270 return &inactive.Chain{Err: errors.New("not a raft chain")} 271 default: 272 return nil 273 } 274 } 275 }) 276 277 It("calls the chain manager and returns the reference when it is found", func() { 278 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 279 Expect(consenter).NotTo(BeNil()) 280 281 chain := consenter.ReceiverByChain("mychannel") 282 Expect(chain).NotTo(BeNil()) 283 Expect(chain).To(BeIdenticalTo(chainInstance)) 284 }) 285 286 It("calls the chain manager and returns nil when it's not found", func() { 287 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 288 Expect(consenter).NotTo(BeNil()) 289 290 chain := consenter.ReceiverByChain("notmychannel") 291 Expect(chain).To(BeNil()) 292 }) 293 294 It("calls the chain manager and returns nil when it's not a raft chain", func() { 295 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 296 Expect(consenter).NotTo(BeNil()) 297 298 chain := consenter.ReceiverByChain("notraftchain") 299 Expect(chain).To(BeNil()) 300 }) 301 }) 302 303 It("successfully constructs a Chain", func() { 304 certAsPEMWithLineFeed := certAsPEM 305 certAsPEMWithLineFeed = append(certAsPEMWithLineFeed, []byte("\n")...) 306 m := &etcdraftproto.ConfigMetadata{ 307 Consenters: []*etcdraftproto.Consenter{ 308 {ServerTlsCert: certAsPEMWithLineFeed}, 309 }, 310 Options: &etcdraftproto.Options{ 311 TickInterval: "500ms", 312 ElectionTick: 10, 313 HeartbeatTick: 1, 314 MaxInflightBlocks: 5, 315 }, 316 } 317 metadata := protoutil.MarshalOrPanic(m) 318 mockOrderer := &mocks.OrdererConfig{} 319 mockOrderer.ConsensusMetadataReturns(metadata) 320 mockOrderer.BatchSizeReturns( 321 &orderer.BatchSize{ 322 PreferredMaxBytes: 2 * 1024 * 1024, 323 }, 324 ) 325 support.SharedConfigReturns(mockOrderer) 326 327 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 328 consenter.EtcdRaftConfig.WALDir = walDir 329 consenter.EtcdRaftConfig.SnapDir = snapDir 330 // consenter.EtcdRaftConfig.EvictionSuspicion is missing 331 var defaultSuspicionFallback bool 332 var trackChainCallback bool 333 consenter.Metrics = newFakeMetrics(newFakeMetricsFields()) 334 consenter.Logger = consenter.Logger.WithOptions(zap.Hooks(func(entry zapcore.Entry) error { 335 if strings.Contains(entry.Message, "EvictionSuspicion not set, defaulting to 10m0s") { 336 defaultSuspicionFallback = true 337 } 338 if strings.Contains(entry.Message, "With system channel: after eviction InactiveChainRegistry.TrackChain will be called") { 339 trackChainCallback = true 340 } 341 return nil 342 })) 343 344 chain, err := consenter.HandleChain(support, nil) 345 Expect(err).NotTo(HaveOccurred()) 346 Expect(chain).NotTo(BeNil()) 347 348 Expect(chain.Start).NotTo(Panic()) 349 Expect(defaultSuspicionFallback).To(BeTrue()) 350 Expect(trackChainCallback).To(BeTrue()) 351 }) 352 353 It("successfully constructs a Chain without a system channel", func() { 354 // We append a line feed to our cert, just to ensure that we can still consume it and ignore. 355 certAsPEMWithLineFeed := certAsPEM 356 certAsPEMWithLineFeed = append(certAsPEMWithLineFeed, []byte("\n")...) 357 m := &etcdraftproto.ConfigMetadata{ 358 Consenters: []*etcdraftproto.Consenter{ 359 {ServerTlsCert: certAsPEMWithLineFeed}, 360 }, 361 Options: &etcdraftproto.Options{ 362 TickInterval: "500ms", 363 ElectionTick: 10, 364 HeartbeatTick: 1, 365 MaxInflightBlocks: 5, 366 }, 367 } 368 metadata := protoutil.MarshalOrPanic(m) 369 mockOrderer := &mocks.OrdererConfig{} 370 mockOrderer.ConsensusMetadataReturns(metadata) 371 mockOrderer.BatchSizeReturns( 372 &orderer.BatchSize{ 373 PreferredMaxBytes: 2 * 1024 * 1024, 374 }, 375 ) 376 support.SharedConfigReturns(mockOrderer) 377 378 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 379 consenter.EtcdRaftConfig.WALDir = walDir 380 consenter.EtcdRaftConfig.SnapDir = snapDir 381 // without a system channel, the InactiveChainRegistry is nil 382 consenter.InactiveChainRegistry = nil 383 consenter.icr = nil 384 385 // consenter.EtcdRaftConfig.EvictionSuspicion is missing 386 var defaultSuspicionFallback bool 387 var switchToFollowerCallback bool 388 consenter.Metrics = newFakeMetrics(newFakeMetricsFields()) 389 consenter.Logger = consenter.Logger.WithOptions(zap.Hooks(func(entry zapcore.Entry) error { 390 if strings.Contains(entry.Message, "EvictionSuspicion not set, defaulting to 10m0s") { 391 defaultSuspicionFallback = true 392 } 393 if strings.Contains(entry.Message, "Without system channel: after eviction Registrar.SwitchToFollower will be called") { 394 switchToFollowerCallback = true 395 } 396 return nil 397 })) 398 399 chain, err := consenter.HandleChain(support, nil) 400 Expect(err).NotTo(HaveOccurred()) 401 Expect(chain).NotTo(BeNil()) 402 403 Expect(chain.Start).NotTo(Panic()) 404 Expect(defaultSuspicionFallback).To(BeTrue()) 405 Expect(switchToFollowerCallback).To(BeTrue()) 406 Expect(chain.Halt).NotTo(Panic()) 407 }) 408 409 It("fails to handle chain if no matching cert found", func() { 410 m := &etcdraftproto.ConfigMetadata{ 411 Consenters: []*etcdraftproto.Consenter{ 412 {ServerTlsCert: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte("foo")})}, 413 }, 414 Options: &etcdraftproto.Options{ 415 TickInterval: "500ms", 416 ElectionTick: 10, 417 HeartbeatTick: 1, 418 MaxInflightBlocks: 5, 419 }, 420 } 421 metadata := protoutil.MarshalOrPanic(m) 422 support := &consensusmocks.FakeConsenterSupport{} 423 mockOrderer := &mocks.OrdererConfig{} 424 mockOrderer.ConsensusMetadataReturns(metadata) 425 mockOrderer.BatchSizeReturns( 426 &orderer.BatchSize{ 427 PreferredMaxBytes: 2 * 1024 * 1024, 428 }, 429 ) 430 support.SharedConfigReturns(mockOrderer) 431 support.ChannelIDReturns("foo") 432 433 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 434 435 chain, err := consenter.HandleChain(support, &common.Metadata{}) 436 Expect(chain).To(Not(BeNil())) 437 Expect(err).To(Not(HaveOccurred())) 438 Expect(chain.Order(nil, 0).Error()).To(Equal("channel foo is not serviced by me")) 439 Expect(consenter.icr.TrackChainCallCount()).To(Equal(1)) 440 Expect(chainManager.ReportConsensusRelationAndStatusMetricsCallCount()).To(Equal(1)) 441 channel, relation, status := chainManager.ReportConsensusRelationAndStatusMetricsArgsForCall(0) 442 Expect(channel).To(Equal("foo")) 443 Expect(relation).To(Equal(types.ConsensusRelationConfigTracker)) 444 Expect(status).To(Equal(types.StatusInactive)) 445 }) 446 447 It("fails to handle chain if etcdraft options have not been provided", func() { 448 m := &etcdraftproto.ConfigMetadata{ 449 Consenters: []*etcdraftproto.Consenter{ 450 {ServerTlsCert: []byte("cert.orderer1.org1")}, 451 }, 452 } 453 metadata := protoutil.MarshalOrPanic(m) 454 mockOrderer := &mocks.OrdererConfig{} 455 mockOrderer.ConsensusMetadataReturns(metadata) 456 mockOrderer.BatchSizeReturns( 457 &orderer.BatchSize{ 458 PreferredMaxBytes: 2 * 1024 * 1024, 459 }, 460 ) 461 support.SharedConfigReturns(mockOrderer) 462 463 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 464 465 chain, err := consenter.HandleChain(support, nil) 466 Expect(chain).To(BeNil()) 467 Expect(err).To(MatchError("etcdraft options have not been provided")) 468 }) 469 470 It("fails to handle chain if tick interval is invalid", func() { 471 m := &etcdraftproto.ConfigMetadata{ 472 Consenters: []*etcdraftproto.Consenter{ 473 {ServerTlsCert: certAsPEM}, 474 }, 475 Options: &etcdraftproto.Options{ 476 TickInterval: "500", 477 ElectionTick: 10, 478 HeartbeatTick: 1, 479 MaxInflightBlocks: 5, 480 }, 481 } 482 metadata := protoutil.MarshalOrPanic(m) 483 mockOrderer := &mocks.OrdererConfig{} 484 mockOrderer.ConsensusMetadataReturns(metadata) 485 mockOrderer.BatchSizeReturns( 486 &orderer.BatchSize{ 487 PreferredMaxBytes: 2 * 1024 * 1024, 488 }, 489 ) 490 mockOrderer.CapabilitiesReturns(&mocks.OrdererCapabilities{}) 491 support.SharedConfigReturns(mockOrderer) 492 493 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 494 495 chain, err := consenter.HandleChain(support, nil) 496 Expect(chain).To(BeNil()) 497 Expect(err).To(MatchError("failed to parse TickInterval (500) to time duration")) 498 }) 499 500 When("the TickIntervalOverride is invalid", func() { 501 It("returns an error", func() { 502 m := &etcdraftproto.ConfigMetadata{ 503 Consenters: []*etcdraftproto.Consenter{ 504 {ServerTlsCert: certAsPEM}, 505 }, 506 Options: &etcdraftproto.Options{ 507 TickInterval: "500", 508 ElectionTick: 10, 509 HeartbeatTick: 1, 510 MaxInflightBlocks: 5, 511 }, 512 } 513 metadata := protoutil.MarshalOrPanic(m) 514 mockOrderer := &mocks.OrdererConfig{} 515 mockOrderer.ConsensusMetadataReturns(metadata) 516 mockOrderer.BatchSizeReturns( 517 &orderer.BatchSize{ 518 PreferredMaxBytes: 2 * 1024 * 1024, 519 }, 520 ) 521 mockOrderer.CapabilitiesReturns(&mocks.OrdererCapabilities{}) 522 support.SharedConfigReturns(mockOrderer) 523 524 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 525 consenter.EtcdRaftConfig.TickIntervalOverride = "seven" 526 527 _, err := consenter.HandleChain(support, nil) 528 Expect(err).To(MatchError(HavePrefix("failed parsing Consensus.TickIntervalOverride:"))) 529 Expect(err).To(MatchError(ContainSubstring("seven"))) 530 }) 531 }) 532 533 It("returns an error if no matching cert found", func() { 534 m := &etcdraftproto.ConfigMetadata{ 535 Consenters: []*etcdraftproto.Consenter{ 536 {ServerTlsCert: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte("foo")})}, 537 }, 538 Options: &etcdraftproto.Options{ 539 TickInterval: "500ms", 540 ElectionTick: 10, 541 HeartbeatTick: 1, 542 MaxInflightBlocks: 5, 543 }, 544 } 545 metadata := protoutil.MarshalOrPanic(m) 546 support := &consensusmocks.FakeConsenterSupport{} 547 mockOrderer := &mocks.OrdererConfig{} 548 mockOrderer.ConsensusMetadataReturns(metadata) 549 mockOrderer.BatchSizeReturns( 550 &orderer.BatchSize{ 551 PreferredMaxBytes: 2 * 1024 * 1024, 552 }, 553 ) 554 support.SharedConfigReturns(mockOrderer) 555 support.ChannelIDReturns("foo") 556 557 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 558 // without a system channel, the InactiveChainRegistry is nil 559 consenter.RemoveInactiveChainRegistry() 560 561 chain, err := consenter.HandleChain(support, &common.Metadata{}) 562 Expect(chain).To((BeNil())) 563 Expect(err).To(MatchError("without a system channel, a follower should have been created: not in the channel")) 564 }) 565 566 It("removes the inactive chain registry (and doesn't panic upon retries)", func() { 567 consenter := newConsenter(chainManager, tlsCA.CertBytes(), certAsPEM) 568 569 consenter.RemoveInactiveChainRegistry() 570 Expect(consenter.icr.StopCallCount()).To(Equal(1)) 571 Expect(consenter.InactiveChainRegistry).To(BeNil()) 572 573 consenter.RemoveInactiveChainRegistry() 574 Expect(consenter.icr.StopCallCount()).To(Equal(1)) 575 }) 576 }) 577 578 type consenter struct { 579 *etcdraft.Consenter 580 icr *mocks.InactiveChainRegistry 581 } 582 583 func newConsenter(chainManager *mocks.ChainManager, caCert, cert []byte) *consenter { 584 communicator := &clustermocks.Communicator{} 585 communicator.On("Configure", mock.Anything, mock.Anything) 586 icr := &mocks.InactiveChainRegistry{} 587 588 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 589 Expect(err).NotTo(HaveOccurred()) 590 591 c := &etcdraft.Consenter{ 592 ChainManager: chainManager, 593 InactiveChainRegistry: icr, 594 Communication: communicator, 595 Cert: cert, 596 Logger: flogging.MustGetLogger("test"), 597 Dispatcher: &etcdraft.Dispatcher{ 598 Logger: flogging.MustGetLogger("test"), 599 ChainSelector: &mocks.ReceiverGetter{}, 600 }, 601 Dialer: &cluster.PredicateDialer{ 602 Config: comm.ClientConfig{ 603 SecOpts: comm.SecureOptions{ 604 Certificate: caCert, 605 }, 606 }, 607 }, 608 BCCSP: cryptoProvider, 609 } 610 return &consenter{ 611 Consenter: c, 612 icr: icr, 613 } 614 }