github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/gossip/state/state_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package state 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "strconv" 24 "sync" 25 "testing" 26 "time" 27 28 pb "github.com/golang/protobuf/proto" 29 "github.com/hyperledger/fabric/common/configtx/test" 30 "github.com/hyperledger/fabric/common/util" 31 "github.com/hyperledger/fabric/core/committer" 32 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 33 "github.com/hyperledger/fabric/core/mocks/validator" 34 "github.com/hyperledger/fabric/gossip/api" 35 "github.com/hyperledger/fabric/gossip/comm" 36 "github.com/hyperledger/fabric/gossip/common" 37 "github.com/hyperledger/fabric/gossip/gossip" 38 "github.com/hyperledger/fabric/gossip/identity" 39 "github.com/hyperledger/fabric/gossip/state/mocks" 40 gutil "github.com/hyperledger/fabric/gossip/util" 41 pcomm "github.com/hyperledger/fabric/protos/common" 42 proto "github.com/hyperledger/fabric/protos/gossip" 43 "github.com/spf13/viper" 44 "github.com/stretchr/testify/assert" 45 "github.com/stretchr/testify/mock" 46 ) 47 48 var ( 49 portPrefix = 5610 50 ) 51 52 var orgID = []byte("ORG1") 53 54 type peerIdentityAcceptor func(identity api.PeerIdentityType) error 55 56 var noopPeerIdentityAcceptor = func(identity api.PeerIdentityType) error { 57 return nil 58 } 59 60 type joinChanMsg struct { 61 } 62 63 func init() { 64 gutil.SetupTestLogging() 65 } 66 67 // SequenceNumber returns the sequence number of the block that the message 68 // is derived from 69 func (*joinChanMsg) SequenceNumber() uint64 { 70 return uint64(time.Now().UnixNano()) 71 } 72 73 // Members returns the organizations of the channel 74 func (jcm *joinChanMsg) Members() []api.OrgIdentityType { 75 return []api.OrgIdentityType{orgID} 76 } 77 78 // AnchorPeersOf returns the anchor peers of the given organization 79 func (jcm *joinChanMsg) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer { 80 return []api.AnchorPeer{} 81 } 82 83 type orgCryptoService struct { 84 } 85 86 // OrgByPeerIdentity returns the OrgIdentityType 87 // of a given peer identity 88 func (*orgCryptoService) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType { 89 return orgID 90 } 91 92 // Verify verifies a JoinChannelMessage, returns nil on success, 93 // and an error on failure 94 func (*orgCryptoService) Verify(joinChanMsg api.JoinChannelMessage) error { 95 return nil 96 } 97 98 type cryptoServiceMock struct { 99 acceptor peerIdentityAcceptor 100 } 101 102 // GetPKIidOfCert returns the PKI-ID of a peer's identity 103 func (*cryptoServiceMock) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType { 104 return common.PKIidType(peerIdentity) 105 } 106 107 // VerifyBlock returns nil if the block is properly signed, 108 // else returns error 109 func (*cryptoServiceMock) VerifyBlock(chainID common.ChainID, signedBlock []byte) error { 110 return nil 111 } 112 113 // Sign signs msg with this peer's signing key and outputs 114 // the signature if no error occurred. 115 func (*cryptoServiceMock) Sign(msg []byte) ([]byte, error) { 116 clone := make([]byte, len(msg)) 117 copy(clone, msg) 118 return clone, nil 119 } 120 121 // Verify checks that signature is a valid signature of message under a peer's verification key. 122 // If the verification succeeded, Verify returns nil meaning no error occurred. 123 // If peerCert is nil, then the signature is verified against this peer's verification key. 124 func (*cryptoServiceMock) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 125 equal := bytes.Equal(signature, message) 126 if !equal { 127 return fmt.Errorf("Wrong signature:%v, %v", signature, message) 128 } 129 return nil 130 } 131 132 // VerifyByChannel checks that signature is a valid signature of message 133 // under a peer's verification key, but also in the context of a specific channel. 134 // If the verification succeeded, Verify returns nil meaning no error occurred. 135 // If peerIdentity is nil, then the signature is verified against this peer's verification key. 136 func (cs *cryptoServiceMock) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 137 return cs.acceptor(peerIdentity) 138 } 139 140 func (*cryptoServiceMock) ValidateIdentity(peerIdentity api.PeerIdentityType) error { 141 return nil 142 } 143 144 func bootPeers(ids ...int) []string { 145 peers := []string{} 146 for _, id := range ids { 147 peers = append(peers, fmt.Sprintf("localhost:%d", id+portPrefix)) 148 } 149 return peers 150 } 151 152 // Simple presentation of peer which includes only 153 // communication module, gossip and state transfer 154 type peerNode struct { 155 port int 156 g gossip.Gossip 157 s GossipStateProvider 158 cs *cryptoServiceMock 159 commit committer.Committer 160 } 161 162 // Shutting down all modules used 163 func (node *peerNode) shutdown() { 164 node.s.Stop() 165 node.g.Stop() 166 } 167 168 type mockCommitter struct { 169 mock.Mock 170 } 171 172 func (mc *mockCommitter) Commit(block *pcomm.Block) error { 173 mc.Called(block) 174 return nil 175 } 176 177 func (mc *mockCommitter) LedgerHeight() (uint64, error) { 178 if mc.Called().Get(1) == nil { 179 return mc.Called().Get(0).(uint64), nil 180 } 181 return mc.Called().Get(0).(uint64), mc.Called().Get(1).(error) 182 } 183 184 func (mc *mockCommitter) GetBlocks(blockSeqs []uint64) []*pcomm.Block { 185 if mc.Called(blockSeqs).Get(0) == nil { 186 return nil 187 } 188 return mc.Called(blockSeqs).Get(0).([]*pcomm.Block) 189 } 190 191 func (*mockCommitter) Close() { 192 } 193 194 // Default configuration to be used for gossip and communication modules 195 func newGossipConfig(id int, boot ...int) *gossip.Config { 196 port := id + portPrefix 197 return &gossip.Config{ 198 BindPort: port, 199 BootstrapPeers: bootPeers(boot...), 200 ID: fmt.Sprintf("p%d", id), 201 MaxBlockCountToStore: 0, 202 MaxPropagationBurstLatency: time.Duration(10) * time.Millisecond, 203 MaxPropagationBurstSize: 10, 204 PropagateIterations: 1, 205 PropagatePeerNum: 3, 206 PullInterval: time.Duration(4) * time.Second, 207 PullPeerNum: 5, 208 InternalEndpoint: fmt.Sprintf("localhost:%d", port), 209 PublishCertPeriod: 10 * time.Second, 210 RequestStateInfoInterval: 4 * time.Second, 211 PublishStateInfoInterval: 4 * time.Second, 212 } 213 } 214 215 // Create gossip instance 216 func newGossipInstance(config *gossip.Config, mcs api.MessageCryptoService) gossip.Gossip { 217 idMapper := identity.NewIdentityMapper(mcs) 218 219 return gossip.NewGossipServiceWithServer(config, &orgCryptoService{}, mcs, idMapper, []byte(config.InternalEndpoint)) 220 } 221 222 // Create new instance of KVLedger to be used for testing 223 func newCommitter(id int) committer.Committer { 224 cb, _ := test.MakeGenesisBlock(strconv.Itoa(id)) 225 ledger, _ := ledgermgmt.CreateLedger(cb) 226 return committer.NewLedgerCommitter(ledger, &validator.MockValidator{}) 227 } 228 229 // Constructing pseudo peer node, simulating only gossip and state transfer part 230 func newPeerNodeWithGossip(config *gossip.Config, committer committer.Committer, acceptor peerIdentityAcceptor, g gossip.Gossip) *peerNode { 231 cs := &cryptoServiceMock{acceptor: acceptor} 232 // Gossip component based on configuration provided and communication module 233 if g == nil { 234 g = newGossipInstance(config, &cryptoServiceMock{acceptor: noopPeerIdentityAcceptor}) 235 } 236 237 logger.Debug("Joinning channel", util.GetTestChainID()) 238 g.JoinChan(&joinChanMsg{}, common.ChainID(util.GetTestChainID())) 239 240 // Initialize pseudo peer simulator, which has only three 241 // basic parts 242 243 sp := NewGossipStateProvider(util.GetTestChainID(), g, committer, cs) 244 if sp == nil { 245 return nil 246 } 247 248 return &peerNode{ 249 port: config.BindPort, 250 g: g, 251 s: sp, 252 commit: committer, 253 cs: cs, 254 } 255 } 256 257 // Constructing pseudo peer node, simulating only gossip and state transfer part 258 func newPeerNode(config *gossip.Config, committer committer.Committer, acceptor peerIdentityAcceptor) *peerNode { 259 return newPeerNodeWithGossip(config, committer, acceptor, nil) 260 } 261 262 func TestNilDirectMsg(t *testing.T) { 263 mc := &mockCommitter{} 264 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 265 g := &mocks.GossipMock{} 266 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 267 g.On("Accept", mock.Anything, true).Return(nil, make(<-chan proto.ReceivedMessage)) 268 p := newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g) 269 defer p.shutdown() 270 p.s.(*GossipStateProviderImpl).handleStateRequest(nil) 271 p.s.(*GossipStateProviderImpl).directMessage(nil) 272 req := &comm.ReceivedMessageImpl{ 273 SignedGossipMessage: p.s.(*GossipStateProviderImpl).stateRequestMessage(uint64(10), uint64(8)).NoopSign(), 274 } 275 p.s.(*GossipStateProviderImpl).directMessage(req) 276 } 277 278 func TestFailures(t *testing.T) { 279 mc := &mockCommitter{} 280 mc.On("LedgerHeight", mock.Anything).Return(uint64(0), nil) 281 g := &mocks.GossipMock{} 282 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 283 g.On("Accept", mock.Anything, true).Return(nil, make(<-chan proto.ReceivedMessage)) 284 assert.Panics(t, func() { 285 newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g) 286 }) 287 // Reprogram mock 288 mc.Mock = mock.Mock{} 289 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), errors.New("Failed accessing ledger")) 290 assert.Nil(t, newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g)) 291 // Reprogram mock 292 mc.Mock = mock.Mock{} 293 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 294 mc.On("GetBlocks", mock.Anything).Return(nil) 295 p := newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g) 296 assert.Nil(t, p.s.GetBlock(uint64(1))) 297 } 298 299 func TestGossipReception(t *testing.T) { 300 signalChan := make(chan struct{}) 301 rawblock := &pcomm.Block{ 302 Header: &pcomm.BlockHeader{ 303 Number: uint64(1), 304 }, 305 Data: &pcomm.BlockData{ 306 Data: [][]byte{}, 307 }, 308 } 309 b, _ := pb.Marshal(rawblock) 310 311 createChan := func(signalChan chan struct{}) <-chan *proto.GossipMessage { 312 c := make(chan *proto.GossipMessage) 313 gMsg := &proto.GossipMessage{ 314 Channel: []byte("AAA"), 315 Content: &proto.GossipMessage_DataMsg{ 316 DataMsg: &proto.DataMessage{ 317 Payload: &proto.Payload{ 318 SeqNum: 1, 319 Data: b, 320 }, 321 }, 322 }, 323 } 324 go func(c chan *proto.GossipMessage) { 325 // Wait for Accept() to be called 326 <-signalChan 327 // Simulate a message reception from the gossip component with an invalid channel 328 c <- gMsg 329 gMsg.Channel = []byte(util.GetTestChainID()) 330 // Simulate a message reception from the gossip component 331 c <- gMsg 332 }(c) 333 return c 334 } 335 336 g := &mocks.GossipMock{} 337 rmc := createChan(signalChan) 338 g.On("Accept", mock.Anything, false).Return(rmc, nil).Run(func(_ mock.Arguments) { 339 signalChan <- struct{}{} 340 }) 341 g.On("Accept", mock.Anything, true).Return(nil, make(<-chan proto.ReceivedMessage)) 342 mc := &mockCommitter{} 343 receivedChan := make(chan struct{}) 344 mc.On("Commit", mock.Anything).Run(func(arguments mock.Arguments) { 345 block := arguments.Get(0).(*pcomm.Block) 346 assert.Equal(t, uint64(1), block.Header.Number) 347 receivedChan <- struct{}{} 348 }) 349 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 350 p := newPeerNodeWithGossip(newGossipConfig(0), mc, noopPeerIdentityAcceptor, g) 351 defer p.shutdown() 352 select { 353 case <-receivedChan: 354 case <-time.After(time.Second * 15): 355 assert.Fail(t, "Didn't commit a block within a timely manner") 356 } 357 } 358 359 func TestAccessControl(t *testing.T) { 360 viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node") 361 ledgermgmt.InitializeTestEnv() 362 defer ledgermgmt.CleanupTestEnv() 363 364 bootstrapSetSize := 5 365 bootstrapSet := make([]*peerNode, 0) 366 367 authorizedPeers := map[string]struct{}{ 368 "localhost:5610": {}, 369 "localhost:5615": {}, 370 "localhost:5618": {}, 371 "localhost:5621": {}, 372 } 373 374 blockPullPolicy := func(identity api.PeerIdentityType) error { 375 if _, isAuthorized := authorizedPeers[string(identity)]; isAuthorized { 376 return nil 377 } 378 return errors.New("Not authorized") 379 } 380 381 for i := 0; i < bootstrapSetSize; i++ { 382 commit := newCommitter(i) 383 bootstrapSet = append(bootstrapSet, newPeerNode(newGossipConfig(i), commit, blockPullPolicy)) 384 } 385 386 defer func() { 387 for _, p := range bootstrapSet { 388 p.shutdown() 389 } 390 }() 391 392 msgCount := 5 393 394 for i := 1; i <= msgCount; i++ { 395 rawblock := pcomm.NewBlock(uint64(i), []byte{}) 396 if b, err := pb.Marshal(rawblock); err == nil { 397 payload := &proto.Payload{uint64(i), "", b} 398 bootstrapSet[0].s.AddPayload(payload) 399 } else { 400 t.Fail() 401 } 402 } 403 404 standardPeerSetSize := 10 405 peersSet := make([]*peerNode, 0) 406 407 for i := 0; i < standardPeerSetSize; i++ { 408 commit := newCommitter(bootstrapSetSize + i) 409 peersSet = append(peersSet, newPeerNode(newGossipConfig(bootstrapSetSize+i, 0, 1, 2, 3, 4), commit, blockPullPolicy)) 410 } 411 412 defer func() { 413 for _, p := range peersSet { 414 p.shutdown() 415 } 416 }() 417 418 waitUntilTrueOrTimeout(t, func() bool { 419 for _, p := range peersSet { 420 if len(p.g.PeersOfChannel(common.ChainID(util.GetTestChainID()))) != bootstrapSetSize+standardPeerSetSize-1 { 421 logger.Debug("Peer discovery has not finished yet") 422 return false 423 } 424 } 425 logger.Debug("All peer discovered each other!!!") 426 return true 427 }, 30*time.Second) 428 429 logger.Debug("Waiting for all blocks to arrive.") 430 waitUntilTrueOrTimeout(t, func() bool { 431 logger.Debug("Trying to see all authorized peers get all blocks, and all non-authorized didn't") 432 for _, p := range peersSet { 433 height, err := p.commit.LedgerHeight() 434 id := fmt.Sprintf("localhost:%d", p.port) 435 if _, isAuthorized := authorizedPeers[id]; isAuthorized { 436 if height != uint64(msgCount+1) || err != nil { 437 return false 438 } 439 } else { 440 if err == nil && height > 1 { 441 assert.Fail(t, "Peer", id, "got message but isn't authorized! Height:", height) 442 } 443 } 444 } 445 logger.Debug("All peers have same ledger height!!!") 446 return true 447 }, 60*time.Second) 448 } 449 450 /*// Simple scenario to start first booting node, gossip a message 451 // then start second node and verify second node also receives it 452 func TestNewGossipStateProvider_GossipingOneMessage(t *testing.T) { 453 bootId := 0 454 ledgerPath := "/tmp/tests/ledger/" 455 defer os.RemoveAll(ledgerPath) 456 457 bootNodeCommitter := newCommitter(bootId, ledgerPath + "node/") 458 defer bootNodeCommitter.Close() 459 460 bootNode := newPeerNode(newGossipConfig(bootId, 100), bootNodeCommitter) 461 defer bootNode.shutdown() 462 463 rawblock := &peer.Block2{} 464 if err := pb.Unmarshal([]byte{}, rawblock); err != nil { 465 t.Fail() 466 } 467 468 if bytes, err := pb.Marshal(rawblock); err == nil { 469 payload := &proto.Payload{1, "", bytes} 470 bootNode.s.AddPayload(payload) 471 } else { 472 t.Fail() 473 } 474 475 waitUntilTrueOrTimeout(t, func() bool { 476 if block := bootNode.s.GetBlock(uint64(1)); block != nil { 477 return true 478 } 479 return false 480 }, 5 * time.Second) 481 482 bootNode.g.Gossip(createDataMsg(uint64(1), []byte{}, "")) 483 484 peerCommitter := newCommitter(1, ledgerPath + "node/") 485 defer peerCommitter.Close() 486 487 peer := newPeerNode(newGossipConfig(1, 100, bootId), peerCommitter) 488 defer peer.shutdown() 489 490 ready := make(chan interface{}) 491 492 go func(p *peerNode) { 493 for len(p.g.GetPeers()) != 1 { 494 time.Sleep(100 * time.Millisecond) 495 } 496 ready <- struct{}{} 497 }(peer) 498 499 select { 500 case <-ready: 501 { 502 break 503 } 504 case <-time.After(1 * time.Second): 505 { 506 t.Fail() 507 } 508 } 509 510 // Let sure anti-entropy will have a chance to bring missing block 511 waitUntilTrueOrTimeout(t, func() bool { 512 if block := peer.s.GetBlock(uint64(1)); block != nil { 513 return true 514 } 515 return false 516 }, 2 * defAntiEntropyInterval + 1 * time.Second) 517 518 block := peer.s.GetBlock(uint64(1)) 519 520 assert.NotNil(t, block) 521 } 522 523 func TestNewGossipStateProvider_RepeatGossipingOneMessage(t *testing.T) { 524 for i := 0; i < 10; i++ { 525 TestNewGossipStateProvider_GossipingOneMessage(t) 526 } 527 }*/ 528 529 func TestNewGossipStateProvider_SendingManyMessages(t *testing.T) { 530 viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node") 531 ledgermgmt.InitializeTestEnv() 532 defer ledgermgmt.CleanupTestEnv() 533 534 bootstrapSetSize := 5 535 bootstrapSet := make([]*peerNode, 0) 536 537 for i := 0; i < bootstrapSetSize; i++ { 538 commit := newCommitter(i) 539 bootstrapSet = append(bootstrapSet, newPeerNode(newGossipConfig(i), commit, noopPeerIdentityAcceptor)) 540 } 541 542 defer func() { 543 for _, p := range bootstrapSet { 544 p.shutdown() 545 } 546 }() 547 548 msgCount := 10 549 550 for i := 1; i <= msgCount; i++ { 551 rawblock := pcomm.NewBlock(uint64(i), []byte{}) 552 if b, err := pb.Marshal(rawblock); err == nil { 553 payload := &proto.Payload{uint64(i), "", b} 554 bootstrapSet[0].s.AddPayload(payload) 555 } else { 556 t.Fail() 557 } 558 } 559 560 standartPeersSize := 10 561 peersSet := make([]*peerNode, 0) 562 563 for i := 0; i < standartPeersSize; i++ { 564 commit := newCommitter(bootstrapSetSize + i) 565 peersSet = append(peersSet, newPeerNode(newGossipConfig(bootstrapSetSize+i, 0, 1, 2, 3, 4), commit, noopPeerIdentityAcceptor)) 566 } 567 568 defer func() { 569 for _, p := range peersSet { 570 p.shutdown() 571 } 572 }() 573 574 waitUntilTrueOrTimeout(t, func() bool { 575 for _, p := range peersSet { 576 if len(p.g.PeersOfChannel(common.ChainID(util.GetTestChainID()))) != bootstrapSetSize+standartPeersSize-1 { 577 logger.Debug("Peer discovery has not finished yet") 578 return false 579 } 580 } 581 logger.Debug("All peer discovered each other!!!") 582 return true 583 }, 30*time.Second) 584 585 logger.Debug("Waiting for all blocks to arrive.") 586 waitUntilTrueOrTimeout(t, func() bool { 587 logger.Debug("Trying to see all peers get all blocks") 588 for _, p := range peersSet { 589 height, err := p.commit.LedgerHeight() 590 if height != uint64(msgCount+1) || err != nil { 591 return false 592 } 593 } 594 logger.Debug("All peers have same ledger height!!!") 595 return true 596 }, 60*time.Second) 597 } 598 599 func TestGossipStateProvider_TestStateMessages(t *testing.T) { 600 viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node") 601 ledgermgmt.InitializeTestEnv() 602 defer ledgermgmt.CleanupTestEnv() 603 604 bootPeer := newPeerNode(newGossipConfig(0), newCommitter(0), noopPeerIdentityAcceptor) 605 defer bootPeer.shutdown() 606 607 peer := newPeerNode(newGossipConfig(1, 0), newCommitter(1), noopPeerIdentityAcceptor) 608 defer peer.shutdown() 609 610 naiveStateMsgPredicate := func(message interface{}) bool { 611 return message.(proto.ReceivedMessage).GetGossipMessage().IsRemoteStateMessage() 612 } 613 614 _, bootCh := bootPeer.g.Accept(naiveStateMsgPredicate, true) 615 _, peerCh := peer.g.Accept(naiveStateMsgPredicate, true) 616 617 wg := sync.WaitGroup{} 618 wg.Add(2) 619 620 go func() { 621 msg := <-bootCh 622 logger.Info("Bootstrap node got message, ", msg) 623 assert.True(t, msg.GetGossipMessage().GetStateRequest() != nil) 624 msg.Respond(&proto.GossipMessage{ 625 Content: &proto.GossipMessage_StateResponse{&proto.RemoteStateResponse{nil}}, 626 }) 627 wg.Done() 628 }() 629 630 go func() { 631 msg := <-peerCh 632 logger.Info("Peer node got an answer, ", msg) 633 assert.True(t, msg.GetGossipMessage().GetStateResponse() != nil) 634 wg.Done() 635 636 }() 637 638 readyCh := make(chan struct{}) 639 go func() { 640 wg.Wait() 641 readyCh <- struct{}{} 642 }() 643 644 time.Sleep(time.Duration(5) * time.Second) 645 logger.Info("Sending gossip message with remote state request") 646 647 chainID := common.ChainID(util.GetTestChainID()) 648 649 peer.g.Send(&proto.GossipMessage{ 650 Content: &proto.GossipMessage_StateRequest{&proto.RemoteStateRequest{0, 1}}, 651 }, &comm.RemotePeer{peer.g.PeersOfChannel(chainID)[0].Endpoint, peer.g.PeersOfChannel(chainID)[0].PKIid}) 652 logger.Info("Waiting until peers exchange messages") 653 654 select { 655 case <-readyCh: 656 { 657 logger.Info("Done!!!") 658 659 } 660 case <-time.After(time.Duration(10) * time.Second): 661 { 662 t.Fail() 663 } 664 } 665 } 666 667 // Start one bootstrap peer and submit defAntiEntropyBatchSize + 5 messages into 668 // local ledger, next spawning a new peer waiting for anti-entropy procedure to 669 // complete missing blocks. Since state transfer messages now batched, it is expected 670 // to see _exactly_ two messages with state transfer response. 671 func TestNewGossipStateProvider_BatchingOfStateRequest(t *testing.T) { 672 viper.Set("peer.fileSystemPath", "/tmp/tests/ledger/node") 673 ledgermgmt.InitializeTestEnv() 674 defer ledgermgmt.CleanupTestEnv() 675 676 bootPeer := newPeerNode(newGossipConfig(0), newCommitter(0), noopPeerIdentityAcceptor) 677 defer bootPeer.shutdown() 678 679 msgCount := defAntiEntropyBatchSize + 5 680 expectedMessagesCnt := 2 681 682 for i := 1; i <= msgCount; i++ { 683 rawblock := pcomm.NewBlock(uint64(i), []byte{}) 684 if b, err := pb.Marshal(rawblock); err == nil { 685 payload := &proto.Payload{uint64(i), "", b} 686 bootPeer.s.AddPayload(payload) 687 } else { 688 t.Fail() 689 } 690 } 691 692 peer := newPeerNode(newGossipConfig(1, 0), newCommitter(1), noopPeerIdentityAcceptor) 693 defer peer.shutdown() 694 695 naiveStateMsgPredicate := func(message interface{}) bool { 696 return message.(proto.ReceivedMessage).GetGossipMessage().IsRemoteStateMessage() 697 } 698 _, peerCh := peer.g.Accept(naiveStateMsgPredicate, true) 699 700 messageCh := make(chan struct{}) 701 stopWaiting := make(chan struct{}) 702 703 // Number of submitted messages is defAntiEntropyBatchSize + 5, therefore 704 // expected number of batches is expectedMessagesCnt = 2. Following go routine 705 // makes sure it receives expected amount of messages and sends signal of success 706 // to continue the test 707 go func(expected int) { 708 cnt := 0 709 for cnt < expected { 710 select { 711 case <-peerCh: 712 { 713 cnt++ 714 } 715 716 case <-stopWaiting: 717 { 718 return 719 } 720 } 721 } 722 723 messageCh <- struct{}{} 724 }(expectedMessagesCnt) 725 726 // Waits for message which indicates that expected number of message batches received 727 // otherwise timeouts after 2 * defAntiEntropyInterval + 1 seconds 728 select { 729 case <-messageCh: 730 { 731 // Once we got message which indicate of two batches being received, 732 // making sure messages indeed committed. 733 waitUntilTrueOrTimeout(t, func() bool { 734 if len(peer.g.PeersOfChannel(common.ChainID(util.GetTestChainID()))) != 1 { 735 logger.Debug("Peer discovery has not finished yet") 736 return false 737 } 738 logger.Debug("All peer discovered each other!!!") 739 return true 740 }, 30*time.Second) 741 742 logger.Debug("Waiting for all blocks to arrive.") 743 waitUntilTrueOrTimeout(t, func() bool { 744 logger.Debug("Trying to see all peers get all blocks") 745 height, err := peer.commit.LedgerHeight() 746 if height != uint64(msgCount+1) || err != nil { 747 return false 748 } 749 logger.Debug("All peers have same ledger height!!!") 750 return true 751 }, 60*time.Second) 752 } 753 case <-time.After(defAntiEntropyInterval*2 + time.Second*1): 754 { 755 close(stopWaiting) 756 t.Fatal("Expected to receive two batches with missing payloads") 757 } 758 } 759 } 760 761 func waitUntilTrueOrTimeout(t *testing.T, predicate func() bool, timeout time.Duration) { 762 ch := make(chan struct{}) 763 go func() { 764 logger.Debug("Started to spin off, until predicate will be satisfied.") 765 for !predicate() { 766 time.Sleep(1 * time.Second) 767 } 768 ch <- struct{}{} 769 logger.Debug("Done.") 770 }() 771 772 select { 773 case <-ch: 774 break 775 case <-time.After(timeout): 776 t.Fatal("Timeout has expired") 777 break 778 } 779 logger.Debug("Stop waiting until timeout or true") 780 }