github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/gossip/state/state_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package state 8 9 import ( 10 "bytes" 11 "errors" 12 "fmt" 13 "math/rand" 14 "net" 15 "sync" 16 "sync/atomic" 17 "testing" 18 "time" 19 20 pb "github.com/golang/protobuf/proto" 21 pcomm "github.com/hyperledger/fabric-protos-go/common" 22 proto "github.com/hyperledger/fabric-protos-go/gossip" 23 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 24 tspb "github.com/hyperledger/fabric-protos-go/transientstore" 25 "github.com/osdi23p228/fabric/bccsp/factory" 26 "github.com/osdi23p228/fabric/common/configtx/test" 27 errors2 "github.com/osdi23p228/fabric/common/errors" 28 "github.com/osdi23p228/fabric/common/flogging" 29 "github.com/osdi23p228/fabric/common/metrics/disabled" 30 "github.com/osdi23p228/fabric/core/committer" 31 "github.com/osdi23p228/fabric/core/committer/txvalidator" 32 "github.com/osdi23p228/fabric/core/ledger" 33 "github.com/osdi23p228/fabric/core/mocks/validator" 34 "github.com/osdi23p228/fabric/core/transientstore" 35 "github.com/osdi23p228/fabric/gossip/api" 36 "github.com/osdi23p228/fabric/gossip/comm" 37 "github.com/osdi23p228/fabric/gossip/common" 38 "github.com/osdi23p228/fabric/gossip/discovery" 39 "github.com/osdi23p228/fabric/gossip/gossip" 40 "github.com/osdi23p228/fabric/gossip/gossip/algo" 41 "github.com/osdi23p228/fabric/gossip/gossip/channel" 42 "github.com/osdi23p228/fabric/gossip/metrics" 43 "github.com/osdi23p228/fabric/gossip/privdata" 44 capabilitymock "github.com/osdi23p228/fabric/gossip/privdata/mocks" 45 "github.com/osdi23p228/fabric/gossip/protoext" 46 "github.com/osdi23p228/fabric/gossip/state/mocks" 47 gossiputil "github.com/osdi23p228/fabric/gossip/util" 48 gutil "github.com/osdi23p228/fabric/gossip/util" 49 corecomm "github.com/osdi23p228/fabric/internal/pkg/comm" 50 "github.com/osdi23p228/fabric/protoutil" 51 "github.com/onsi/gomega" 52 "github.com/onsi/gomega/gbytes" 53 "github.com/stretchr/testify/assert" 54 "github.com/stretchr/testify/mock" 55 "go.uber.org/zap" 56 "go.uber.org/zap/zapcore" 57 ) 58 59 var ( 60 orgID = []byte("ORG1") 61 62 noopPeerIdentityAcceptor = func(identity api.PeerIdentityType) error { 63 return nil 64 } 65 ) 66 67 type peerIdentityAcceptor func(identity api.PeerIdentityType) error 68 69 type joinChanMsg struct { 70 } 71 72 func init() { 73 gutil.SetupTestLogging() 74 factory.InitFactories(nil) 75 } 76 77 // SequenceNumber returns the sequence number of the block that the message 78 // is derived from 79 func (*joinChanMsg) SequenceNumber() uint64 { 80 return uint64(time.Now().UnixNano()) 81 } 82 83 // Members returns the organizations of the channel 84 func (jcm *joinChanMsg) Members() []api.OrgIdentityType { 85 return []api.OrgIdentityType{orgID} 86 } 87 88 // AnchorPeersOf returns the anchor peers of the given organization 89 func (jcm *joinChanMsg) AnchorPeersOf(org api.OrgIdentityType) []api.AnchorPeer { 90 return []api.AnchorPeer{} 91 } 92 93 type orgCryptoService struct { 94 } 95 96 // OrgByPeerIdentity returns the OrgIdentityType 97 // of a given peer identity 98 func (*orgCryptoService) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType { 99 return orgID 100 } 101 102 // Verify verifies a JoinChannelMessage, returns nil on success, 103 // and an error on failure 104 func (*orgCryptoService) Verify(joinChanMsg api.JoinChannelMessage) error { 105 return nil 106 } 107 108 type cryptoServiceMock struct { 109 acceptor peerIdentityAcceptor 110 } 111 112 func (cryptoServiceMock) Expiration(peerIdentity api.PeerIdentityType) (time.Time, error) { 113 return time.Now().Add(time.Hour), nil 114 } 115 116 // GetPKIidOfCert returns the PKI-ID of a peer's identity 117 func (*cryptoServiceMock) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType { 118 return common.PKIidType(peerIdentity) 119 } 120 121 // VerifyBlock returns nil if the block is properly signed, 122 // else returns error 123 func (*cryptoServiceMock) VerifyBlock(channelID common.ChannelID, seqNum uint64, signedBlock *pcomm.Block) error { 124 return nil 125 } 126 127 // Sign signs msg with this peer's signing key and outputs 128 // the signature if no error occurred. 129 func (*cryptoServiceMock) Sign(msg []byte) ([]byte, error) { 130 clone := make([]byte, len(msg)) 131 copy(clone, msg) 132 return clone, nil 133 } 134 135 // Verify checks that signature is a valid signature of message under a peer's verification key. 136 // If the verification succeeded, Verify returns nil meaning no error occurred. 137 // If peerCert is nil, then the signature is verified against this peer's verification key. 138 func (*cryptoServiceMock) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 139 equal := bytes.Equal(signature, message) 140 if !equal { 141 return fmt.Errorf("Wrong signature:%v, %v", signature, message) 142 } 143 return nil 144 } 145 146 // VerifyByChannel checks that signature is a valid signature of message 147 // under a peer's verification key, but also in the context of a specific channel. 148 // If the verification succeeded, Verify returns nil meaning no error occurred. 149 // If peerIdentity is nil, then the signature is verified against this peer's verification key. 150 func (cs *cryptoServiceMock) VerifyByChannel(channelID common.ChannelID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 151 return cs.acceptor(peerIdentity) 152 } 153 154 func (*cryptoServiceMock) ValidateIdentity(peerIdentity api.PeerIdentityType) error { 155 return nil 156 } 157 158 func bootPeersWithPorts(ports ...int) []string { 159 var peers []string 160 for _, port := range ports { 161 peers = append(peers, fmt.Sprintf("127.0.0.1:%d", port)) 162 } 163 return peers 164 } 165 166 type peerNodeGossipSupport interface { 167 GossipAdapter 168 Stop() 169 JoinChan(joinMsg api.JoinChannelMessage, channelID common.ChannelID) 170 } 171 172 // Simple presentation of peer which includes only 173 // communication module, gossip and state transfer 174 type peerNode struct { 175 port int 176 g peerNodeGossipSupport 177 s *GossipStateProviderImpl 178 cs *cryptoServiceMock 179 commit committer.Committer 180 grpc *corecomm.GRPCServer 181 } 182 183 // Shutting down all modules used 184 func (node *peerNode) shutdown() { 185 node.s.Stop() 186 node.g.Stop() 187 node.grpc.Stop() 188 } 189 190 type mockCommitter struct { 191 *mock.Mock 192 sync.Mutex 193 } 194 195 func (mc *mockCommitter) GetConfigHistoryRetriever() (ledger.ConfigHistoryRetriever, error) { 196 args := mc.Called() 197 return args.Get(0).(ledger.ConfigHistoryRetriever), args.Error(1) 198 } 199 200 func (mc *mockCommitter) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) { 201 args := mc.Called(blockNum, filter) 202 return args.Get(0).([]*ledger.TxPvtData), args.Error(1) 203 } 204 205 func (mc *mockCommitter) CommitLegacy(blockAndPvtData *ledger.BlockAndPvtData, commitOpts *ledger.CommitOptions) error { 206 mc.Lock() 207 m := mc.Mock 208 mc.Unlock() 209 m.Called(blockAndPvtData.Block) 210 return nil 211 } 212 213 func (mc *mockCommitter) GetPvtDataAndBlockByNum(seqNum uint64) (*ledger.BlockAndPvtData, error) { 214 mc.Lock() 215 m := mc.Mock 216 mc.Unlock() 217 218 args := m.Called(seqNum) 219 return args.Get(0).(*ledger.BlockAndPvtData), args.Error(1) 220 } 221 222 func (mc *mockCommitter) LedgerHeight() (uint64, error) { 223 mc.Lock() 224 m := mc.Mock 225 mc.Unlock() 226 args := m.Called() 227 if args.Get(1) == nil { 228 return args.Get(0).(uint64), nil 229 } 230 return args.Get(0).(uint64), args.Get(1).(error) 231 } 232 233 func (mc *mockCommitter) DoesPvtDataInfoExistInLedger(blkNum uint64) (bool, error) { 234 mc.Lock() 235 m := mc.Mock 236 mc.Unlock() 237 args := m.Called(blkNum) 238 return args.Get(0).(bool), args.Error(1) 239 } 240 241 func (mc *mockCommitter) GetBlocks(blockSeqs []uint64) []*pcomm.Block { 242 mc.Lock() 243 m := mc.Mock 244 mc.Unlock() 245 246 if m.Called(blockSeqs).Get(0) == nil { 247 return nil 248 } 249 return m.Called(blockSeqs).Get(0).([]*pcomm.Block) 250 } 251 252 func (*mockCommitter) GetMissingPvtDataTracker() (ledger.MissingPvtDataTracker, error) { 253 panic("implement me") 254 } 255 256 func (*mockCommitter) CommitPvtDataOfOldBlocks( 257 reconciledPvtdata []*ledger.ReconciledPvtdata, 258 unreconciled ledger.MissingPvtDataInfo, 259 ) ([]*ledger.PvtdataHashMismatch, error) { 260 panic("implement me") 261 } 262 263 func (*mockCommitter) Close() { 264 } 265 266 type ramLedger struct { 267 ledger map[uint64]*ledger.BlockAndPvtData 268 sync.RWMutex 269 } 270 271 func (mock *ramLedger) GetMissingPvtDataTracker() (ledger.MissingPvtDataTracker, error) { 272 panic("implement me") 273 } 274 275 func (mock *ramLedger) CommitPvtDataOfOldBlocks( 276 reconciledPvtdata []*ledger.ReconciledPvtdata, 277 unreconciled ledger.MissingPvtDataInfo, 278 ) ([]*ledger.PvtdataHashMismatch, error) { 279 panic("implement me") 280 } 281 282 func (mock *ramLedger) GetConfigHistoryRetriever() (ledger.ConfigHistoryRetriever, error) { 283 panic("implement me") 284 } 285 286 func (mock *ramLedger) GetPvtDataAndBlockByNum(blockNum uint64, filter ledger.PvtNsCollFilter) (*ledger.BlockAndPvtData, error) { 287 mock.RLock() 288 defer mock.RUnlock() 289 290 if block, ok := mock.ledger[blockNum]; !ok { 291 return nil, fmt.Errorf("no block with seq = %d found", blockNum) 292 } else { 293 return block, nil 294 } 295 } 296 297 func (mock *ramLedger) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) { 298 panic("implement me") 299 } 300 301 func (mock *ramLedger) CommitLegacy(blockAndPvtdata *ledger.BlockAndPvtData, commitOpts *ledger.CommitOptions) error { 302 mock.Lock() 303 defer mock.Unlock() 304 305 if blockAndPvtdata != nil && blockAndPvtdata.Block != nil { 306 mock.ledger[blockAndPvtdata.Block.Header.Number] = blockAndPvtdata 307 return nil 308 } 309 return errors.New("invalid input parameters for block and private data param") 310 } 311 312 func (mock *ramLedger) GetBlockchainInfo() (*pcomm.BlockchainInfo, error) { 313 mock.RLock() 314 defer mock.RUnlock() 315 316 currentBlock := mock.ledger[uint64(len(mock.ledger)-1)].Block 317 return &pcomm.BlockchainInfo{ 318 Height: currentBlock.Header.Number + 1, 319 CurrentBlockHash: protoutil.BlockHeaderHash(currentBlock.Header), 320 PreviousBlockHash: currentBlock.Header.PreviousHash, 321 }, nil 322 } 323 324 func (mock *ramLedger) DoesPvtDataInfoExist(blkNum uint64) (bool, error) { 325 return false, nil 326 } 327 328 func (mock *ramLedger) GetBlockByNumber(blockNumber uint64) (*pcomm.Block, error) { 329 mock.RLock() 330 defer mock.RUnlock() 331 332 if blockAndPvtData, ok := mock.ledger[blockNumber]; !ok { 333 return nil, fmt.Errorf("no block with seq = %d found", blockNumber) 334 } else { 335 return blockAndPvtData.Block, nil 336 } 337 } 338 339 func (mock *ramLedger) Close() { 340 341 } 342 343 // Create new instance of KVLedger to be used for testing 344 func newCommitter() committer.Committer { 345 cb, _ := test.MakeGenesisBlock("testChain") 346 ldgr := &ramLedger{ 347 ledger: make(map[uint64]*ledger.BlockAndPvtData), 348 } 349 ldgr.CommitLegacy(&ledger.BlockAndPvtData{Block: cb}, &ledger.CommitOptions{}) 350 return committer.NewLedgerCommitter(ldgr) 351 } 352 353 func newPeerNodeWithGossip(id int, committer committer.Committer, 354 acceptor peerIdentityAcceptor, g peerNodeGossipSupport, bootPorts ...int) *peerNode { 355 logger := flogging.MustGetLogger(gutil.StateLogger) 356 return newPeerNodeWithGossipWithValidator(logger, id, committer, acceptor, g, &validator.MockValidator{}, bootPorts...) 357 } 358 359 // Constructing pseudo peer node, simulating only gossip and state transfer part 360 func newPeerNodeWithGossipWithValidatorWithMetrics(logger gutil.Logger, id int, committer committer.Committer, 361 acceptor peerIdentityAcceptor, g peerNodeGossipSupport, v txvalidator.Validator, 362 gossipMetrics *metrics.GossipMetrics, bootPorts ...int) (node *peerNode, port int) { 363 cs := &cryptoServiceMock{acceptor: acceptor} 364 port, gRPCServer, certs, secureDialOpts, _ := gossiputil.CreateGRPCLayer() 365 366 if g == nil { 367 config := &gossip.Config{ 368 BindPort: port, 369 BootstrapPeers: bootPeersWithPorts(bootPorts...), 370 ID: fmt.Sprintf("p%d", id), 371 MaxBlockCountToStore: 0, 372 MaxPropagationBurstLatency: time.Duration(10) * time.Millisecond, 373 MaxPropagationBurstSize: 10, 374 PropagateIterations: 1, 375 PropagatePeerNum: 3, 376 PullInterval: time.Duration(4) * time.Second, 377 PullPeerNum: 5, 378 InternalEndpoint: fmt.Sprintf("127.0.0.1:%d", port), 379 PublishCertPeriod: 10 * time.Second, 380 RequestStateInfoInterval: 4 * time.Second, 381 PublishStateInfoInterval: 4 * time.Second, 382 TimeForMembershipTracker: 5 * time.Second, 383 TLSCerts: certs, 384 DigestWaitTime: algo.DefDigestWaitTime, 385 RequestWaitTime: algo.DefRequestWaitTime, 386 ResponseWaitTime: algo.DefResponseWaitTime, 387 DialTimeout: comm.DefDialTimeout, 388 ConnTimeout: comm.DefConnTimeout, 389 RecvBuffSize: comm.DefRecvBuffSize, 390 SendBuffSize: comm.DefSendBuffSize, 391 MsgExpirationTimeout: channel.DefMsgExpirationTimeout, 392 AliveTimeInterval: discovery.DefAliveTimeInterval, 393 AliveExpirationTimeout: discovery.DefAliveExpirationTimeout, 394 AliveExpirationCheckInterval: discovery.DefAliveExpirationCheckInterval, 395 ReconnectInterval: discovery.DefReconnectInterval, 396 MaxConnectionAttempts: discovery.DefMaxConnectionAttempts, 397 MsgExpirationFactor: discovery.DefMsgExpirationFactor, 398 } 399 400 selfID := api.PeerIdentityType(config.InternalEndpoint) 401 mcs := &cryptoServiceMock{acceptor: noopPeerIdentityAcceptor} 402 g = gossip.New(config, gRPCServer.Server(), &orgCryptoService{}, mcs, selfID, secureDialOpts, gossipMetrics, nil) 403 } 404 405 g.JoinChan(&joinChanMsg{}, common.ChannelID("testchannelid")) 406 407 go func() { 408 gRPCServer.Start() 409 }() 410 411 // Initialize pseudo peer simulator, which has only three 412 // basic parts 413 414 servicesAdapater := &ServicesMediator{GossipAdapter: g, MCSAdapter: cs} 415 coordConfig := privdata.CoordinatorConfig{ 416 PullRetryThreshold: 0, 417 TransientBlockRetention: 1000, 418 SkipPullingInvalidTransactions: false, 419 } 420 421 mspID := "Org1MSP" 422 capabilityProvider := &capabilitymock.CapabilityProvider{} 423 appCapability := &capabilitymock.AppCapabilities{} 424 capabilityProvider.On("Capabilities").Return(appCapability) 425 appCapability.On("StorePvtDataOfInvalidTx").Return(true) 426 coord := privdata.NewCoordinator(mspID, privdata.Support{ 427 Validator: v, 428 Committer: committer, 429 CapabilityProvider: capabilityProvider, 430 }, &transientstore.Store{}, protoutil.SignedData{}, gossipMetrics.PrivdataMetrics, coordConfig, nil) 431 stateConfig := &StateConfig{ 432 StateCheckInterval: DefStateCheckInterval, 433 StateResponseTimeout: DefStateResponseTimeout, 434 StateBatchSize: DefStateBatchSize, 435 StateMaxRetries: DefStateMaxRetries, 436 StateBlockBufferSize: DefStateBlockBufferSize, 437 StateChannelSize: DefStateChannelSize, 438 StateEnabled: true, 439 } 440 sp := NewGossipStateProvider(logger, "testchannelid", servicesAdapater, coord, gossipMetrics.StateMetrics, blocking, stateConfig) 441 if sp == nil { 442 gRPCServer.Stop() 443 return nil, port 444 } 445 446 return &peerNode{ 447 port: port, 448 g: g, 449 s: sp.(*GossipStateProviderImpl), 450 commit: committer, 451 cs: cs, 452 grpc: gRPCServer, 453 }, port 454 455 } 456 457 // add metrics provider for metrics testing 458 func newPeerNodeWithGossipWithMetrics(id int, committer committer.Committer, 459 acceptor peerIdentityAcceptor, g peerNodeGossipSupport, gossipMetrics *metrics.GossipMetrics) *peerNode { 460 logger := flogging.MustGetLogger(gutil.StateLogger) 461 node, _ := newPeerNodeWithGossipWithValidatorWithMetrics(logger, id, committer, acceptor, g, 462 &validator.MockValidator{}, gossipMetrics) 463 return node 464 } 465 466 // Constructing pseudo peer node, simulating only gossip and state transfer part 467 func newPeerNodeWithGossipWithValidator(logger gutil.Logger, id int, committer committer.Committer, 468 acceptor peerIdentityAcceptor, g peerNodeGossipSupport, v txvalidator.Validator, bootPorts ...int) *peerNode { 469 gossipMetrics := metrics.NewGossipMetrics(&disabled.Provider{}) 470 node, _ := newPeerNodeWithGossipWithValidatorWithMetrics(logger, id, committer, acceptor, g, v, gossipMetrics, bootPorts...) 471 return node 472 } 473 474 // Constructing pseudo peer node, simulating only gossip and state transfer part 475 func newPeerNode(id int, committer committer.Committer, acceptor peerIdentityAcceptor, bootPorts ...int) *peerNode { 476 return newPeerNodeWithGossip(id, committer, acceptor, nil, bootPorts...) 477 } 478 479 // Constructing pseudo boot node, simulating only gossip and state transfer part, return port 480 func newBootNode(id int, committer committer.Committer, acceptor peerIdentityAcceptor) (node *peerNode, port int) { 481 v := &validator.MockValidator{} 482 gossipMetrics := metrics.NewGossipMetrics(&disabled.Provider{}) 483 logger := flogging.MustGetLogger(gutil.StateLogger) 484 return newPeerNodeWithGossipWithValidatorWithMetrics(logger, id, committer, acceptor, nil, v, gossipMetrics) 485 } 486 487 func TestStraggler(t *testing.T) { 488 for _, testCase := range []struct { 489 stateEnabled bool 490 orgLeader bool 491 leaderElection bool 492 height uint64 493 receivedSeq uint64 494 expected bool 495 }{ 496 { 497 height: 100, 498 receivedSeq: 300, 499 leaderElection: true, 500 expected: true, 501 }, 502 { 503 height: 100, 504 receivedSeq: 300, 505 expected: true, 506 }, 507 { 508 height: 100, 509 receivedSeq: 300, 510 orgLeader: true, 511 }, 512 { 513 height: 100, 514 receivedSeq: 105, 515 leaderElection: true, 516 }, 517 { 518 height: 100, 519 receivedSeq: 300, 520 leaderElection: true, 521 stateEnabled: true, 522 }, 523 } { 524 description := fmt.Sprintf("%+v", testCase) 525 t.Run(description, func(t *testing.T) { 526 s := &GossipStateProviderImpl{ 527 config: &StateConfig{ 528 StateEnabled: testCase.stateEnabled, 529 OrgLeader: testCase.orgLeader, 530 UseLeaderElection: testCase.leaderElection, 531 }, 532 } 533 534 s.straggler(testCase.height, &proto.Payload{ 535 SeqNum: testCase.receivedSeq, 536 }) 537 }) 538 } 539 540 } 541 542 func TestNilDirectMsg(t *testing.T) { 543 mc := &mockCommitter{Mock: &mock.Mock{}} 544 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 545 g := &mocks.GossipMock{} 546 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 547 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 548 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 549 defer p.shutdown() 550 p.s.handleStateRequest(nil) 551 p.s.directMessage(nil) 552 sMsg, _ := protoext.NoopSign(p.s.stateRequestMessage(uint64(10), uint64(8))) 553 req := &comm.ReceivedMessageImpl{ 554 SignedGossipMessage: sMsg, 555 } 556 p.s.directMessage(req) 557 } 558 559 func TestNilAddPayload(t *testing.T) { 560 mc := &mockCommitter{Mock: &mock.Mock{}} 561 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 562 g := &mocks.GossipMock{} 563 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 564 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 565 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 566 defer p.shutdown() 567 err := p.s.AddPayload(nil) 568 assert.Error(t, err) 569 assert.Contains(t, err.Error(), "nil") 570 } 571 572 func TestAddPayloadLedgerUnavailable(t *testing.T) { 573 mc := &mockCommitter{Mock: &mock.Mock{}} 574 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 575 g := &mocks.GossipMock{} 576 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 577 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 578 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 579 defer p.shutdown() 580 // Simulate a problem in the ledger 581 failedLedger := mock.Mock{} 582 failedLedger.On("LedgerHeight", mock.Anything).Return(uint64(0), errors.New("cannot query ledger")) 583 mc.Lock() 584 mc.Mock = &failedLedger 585 mc.Unlock() 586 587 rawblock := protoutil.NewBlock(uint64(1), []byte{}) 588 b, _ := pb.Marshal(rawblock) 589 err := p.s.AddPayload(&proto.Payload{ 590 SeqNum: uint64(1), 591 Data: b, 592 }) 593 assert.Error(t, err) 594 assert.Contains(t, err.Error(), "Failed obtaining ledger height") 595 assert.Contains(t, err.Error(), "cannot query ledger") 596 } 597 598 func TestLargeBlockGap(t *testing.T) { 599 // Scenario: the peer knows of a peer who has a ledger height much higher 600 // than itself (500 blocks higher). 601 // The peer needs to ask blocks in a way such that the size of the payload buffer 602 // never rises above a certain threshold. 603 mc := &mockCommitter{Mock: &mock.Mock{}} 604 blocksPassedToLedger := make(chan uint64, 200) 605 mc.On("CommitLegacy", mock.Anything).Run(func(arg mock.Arguments) { 606 blocksPassedToLedger <- arg.Get(0).(*pcomm.Block).Header.Number 607 }) 608 msgsFromPeer := make(chan protoext.ReceivedMessage) 609 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 610 mc.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 611 g := &mocks.GossipMock{} 612 membership := []discovery.NetworkMember{ 613 { 614 PKIid: common.PKIidType("a"), 615 Endpoint: "a", 616 Properties: &proto.Properties{ 617 LedgerHeight: 500, 618 }, 619 }} 620 g.On("PeersOfChannel", mock.Anything).Return(membership) 621 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 622 g.On("Accept", mock.Anything, true).Return(nil, msgsFromPeer) 623 g.On("Send", mock.Anything, mock.Anything).Run(func(arguments mock.Arguments) { 624 msg := arguments.Get(0).(*proto.GossipMessage) 625 // The peer requested a state request 626 req := msg.GetStateRequest() 627 // Construct a skeleton for the response 628 res := &proto.GossipMessage{ 629 Nonce: msg.Nonce, 630 Channel: []byte("testchannelid"), 631 Content: &proto.GossipMessage_StateResponse{ 632 StateResponse: &proto.RemoteStateResponse{}, 633 }, 634 } 635 // Populate the response with payloads according to what the peer asked 636 for seq := req.StartSeqNum; seq <= req.EndSeqNum; seq++ { 637 rawblock := protoutil.NewBlock(seq, []byte{}) 638 b, _ := pb.Marshal(rawblock) 639 payload := &proto.Payload{ 640 SeqNum: seq, 641 Data: b, 642 } 643 res.GetStateResponse().Payloads = append(res.GetStateResponse().Payloads, payload) 644 } 645 // Finally, send the response down the channel the peer expects to receive it from 646 sMsg, _ := protoext.NoopSign(res) 647 msgsFromPeer <- &comm.ReceivedMessageImpl{ 648 SignedGossipMessage: sMsg, 649 } 650 }) 651 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 652 defer p.shutdown() 653 654 // Process blocks at a speed of 20 Millisecond for each block. 655 // The imaginative peer that responds to state 656 // If the payload buffer expands above defMaxBlockDistance*2 + defAntiEntropyBatchSize blocks, fail the test 657 blockProcessingTime := 20 * time.Millisecond // 10 seconds for total 500 blocks 658 expectedSequence := 1 659 for expectedSequence < 500 { 660 blockSeq := <-blocksPassedToLedger 661 assert.Equal(t, expectedSequence, int(blockSeq)) 662 // Ensure payload buffer isn't over-populated 663 assert.True(t, p.s.payloads.Size() <= defMaxBlockDistance*2+defAntiEntropyBatchSize, "payload buffer size is %d", p.s.payloads.Size()) 664 expectedSequence++ 665 time.Sleep(blockProcessingTime) 666 } 667 } 668 669 func TestOverPopulation(t *testing.T) { 670 // Scenario: Add to the state provider blocks 671 // with a gap in between, and ensure that the payload buffer 672 // rejects blocks starting if the distance between the ledger height to the latest 673 // block it contains is bigger than defMaxBlockDistance. 674 mc := &mockCommitter{Mock: &mock.Mock{}} 675 blocksPassedToLedger := make(chan uint64, 10) 676 mc.On("CommitLegacy", mock.Anything).Run(func(arg mock.Arguments) { 677 blocksPassedToLedger <- arg.Get(0).(*pcomm.Block).Header.Number 678 }) 679 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 680 mc.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 681 g := &mocks.GossipMock{} 682 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 683 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 684 p := newPeerNode(0, mc, noopPeerIdentityAcceptor) 685 defer p.shutdown() 686 687 // Add some blocks in a sequential manner and make sure it works 688 for i := 1; i <= 4; i++ { 689 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 690 b, _ := pb.Marshal(rawblock) 691 assert.NoError(t, p.s.addPayload(&proto.Payload{ 692 SeqNum: uint64(i), 693 Data: b, 694 }, nonBlocking)) 695 } 696 697 // Add payloads from 10 to defMaxBlockDistance, while we're missing blocks [5,9] 698 // Should succeed 699 for i := 10; i <= defMaxBlockDistance; i++ { 700 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 701 b, _ := pb.Marshal(rawblock) 702 assert.NoError(t, p.s.addPayload(&proto.Payload{ 703 SeqNum: uint64(i), 704 Data: b, 705 }, nonBlocking)) 706 } 707 708 // Add payloads from defMaxBlockDistance + 2 to defMaxBlockDistance * 10 709 // Should fail. 710 for i := defMaxBlockDistance + 1; i <= defMaxBlockDistance*10; i++ { 711 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 712 b, _ := pb.Marshal(rawblock) 713 assert.Error(t, p.s.addPayload(&proto.Payload{ 714 SeqNum: uint64(i), 715 Data: b, 716 }, nonBlocking)) 717 } 718 719 // Ensure only blocks 1-4 were passed to the ledger 720 close(blocksPassedToLedger) 721 i := 1 722 for seq := range blocksPassedToLedger { 723 assert.Equal(t, uint64(i), seq) 724 i++ 725 } 726 assert.Equal(t, 5, i) 727 728 // Ensure we don't store too many blocks in memory 729 sp := p.s 730 assert.True(t, sp.payloads.Size() < defMaxBlockDistance) 731 } 732 733 func TestBlockingEnqueue(t *testing.T) { 734 // Scenario: In parallel, get blocks from gossip and from the orderer. 735 // The blocks from the orderer we get are X2 times the amount of blocks from gossip. 736 // The blocks we get from gossip are random indices, to maximize disruption. 737 mc := &mockCommitter{Mock: &mock.Mock{}} 738 blocksPassedToLedger := make(chan uint64, 10) 739 mc.On("CommitLegacy", mock.Anything).Run(func(arg mock.Arguments) { 740 blocksPassedToLedger <- arg.Get(0).(*pcomm.Block).Header.Number 741 }) 742 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 743 mc.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 744 g := &mocks.GossipMock{} 745 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 746 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 747 p := newPeerNode(0, mc, noopPeerIdentityAcceptor) 748 defer p.shutdown() 749 750 numBlocksReceived := 500 751 receivedBlockCount := 0 752 // Get a block from the orderer every 1ms 753 go func() { 754 for i := 1; i <= numBlocksReceived; i++ { 755 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 756 b, _ := pb.Marshal(rawblock) 757 block := &proto.Payload{ 758 SeqNum: uint64(i), 759 Data: b, 760 } 761 p.s.AddPayload(block) 762 time.Sleep(time.Millisecond) 763 } 764 }() 765 766 // Get a block from gossip every 1ms too 767 go func() { 768 rand.Seed(time.Now().UnixNano()) 769 for i := 1; i <= numBlocksReceived/2; i++ { 770 blockSeq := rand.Intn(numBlocksReceived) 771 rawblock := protoutil.NewBlock(uint64(blockSeq), []byte{}) 772 b, _ := pb.Marshal(rawblock) 773 block := &proto.Payload{ 774 SeqNum: uint64(blockSeq), 775 Data: b, 776 } 777 p.s.addPayload(block, nonBlocking) 778 time.Sleep(time.Millisecond) 779 } 780 }() 781 782 for { 783 receivedBlock := <-blocksPassedToLedger 784 receivedBlockCount++ 785 m := &mock.Mock{} 786 m.On("LedgerHeight", mock.Anything).Return(receivedBlock, nil) 787 m.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 788 m.On("CommitLegacy", mock.Anything).Run(func(arg mock.Arguments) { 789 blocksPassedToLedger <- arg.Get(0).(*pcomm.Block).Header.Number 790 }) 791 mc.Lock() 792 mc.Mock = m 793 mc.Unlock() 794 assert.Equal(t, receivedBlock, uint64(receivedBlockCount)) 795 if int(receivedBlockCount) == numBlocksReceived { 796 break 797 } 798 time.Sleep(time.Millisecond * 10) 799 } 800 } 801 802 func TestHaltChainProcessing(t *testing.T) { 803 gossipChannel := func(c chan *proto.GossipMessage) <-chan *proto.GossipMessage { 804 return c 805 } 806 makeBlock := func(seq int) []byte { 807 b := &pcomm.Block{ 808 Header: &pcomm.BlockHeader{ 809 Number: uint64(seq), 810 }, 811 Data: &pcomm.BlockData{ 812 Data: [][]byte{}, 813 }, 814 Metadata: &pcomm.BlockMetadata{ 815 Metadata: [][]byte{ 816 {}, {}, {}, {}, 817 }, 818 }, 819 } 820 data, _ := pb.Marshal(b) 821 return data 822 } 823 newBlockMsg := func(i int) *proto.GossipMessage { 824 return &proto.GossipMessage{ 825 Channel: []byte("testchannelid"), 826 Content: &proto.GossipMessage_DataMsg{ 827 DataMsg: &proto.DataMessage{ 828 Payload: &proto.Payload{ 829 SeqNum: uint64(i), 830 Data: makeBlock(i), 831 }, 832 }, 833 }, 834 } 835 } 836 837 mc := &mockCommitter{Mock: &mock.Mock{}} 838 mc.On("CommitLegacy", mock.Anything) 839 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 840 g := &mocks.GossipMock{} 841 gossipMsgs := make(chan *proto.GossipMessage) 842 843 g.On("Accept", mock.Anything, false).Return(gossipChannel(gossipMsgs), nil) 844 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 845 g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{}) 846 847 v := &validator.MockValidator{} 848 v.On("Validate").Return(&errors2.VSCCExecutionFailureError{ 849 Err: errors.New("foobar"), 850 }).Once() 851 852 buf := gbytes.NewBuffer() 853 854 logger := flogging.MustGetLogger(gutil.StateLogger).WithOptions(zap.Hooks(func(entry zapcore.Entry) error { 855 buf.Write([]byte(entry.Message)) 856 buf.Write([]byte("\n")) 857 return nil 858 })) 859 peerNode := newPeerNodeWithGossipWithValidator(logger, 0, mc, noopPeerIdentityAcceptor, g, v) 860 defer peerNode.shutdown() 861 gossipMsgs <- newBlockMsg(1) 862 863 gom := gomega.NewGomegaWithT(t) 864 gom.Eventually(buf, time.Minute).Should(gbytes.Say("Failed executing VSCC due to foobar")) 865 gom.Eventually(buf, time.Minute).Should(gbytes.Say("Aborting chain processing")) 866 } 867 868 func TestFailures(t *testing.T) { 869 mc := &mockCommitter{Mock: &mock.Mock{}} 870 mc.On("LedgerHeight", mock.Anything).Return(uint64(0), nil) 871 g := &mocks.GossipMock{} 872 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 873 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 874 g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{}) 875 assert.Panics(t, func() { 876 newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 877 }) 878 // Reprogram mock 879 mc.Mock = &mock.Mock{} 880 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), errors.New("Failed accessing ledger")) 881 assert.Nil(t, newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g)) 882 } 883 884 func TestGossipReception(t *testing.T) { 885 signalChan := make(chan struct{}) 886 rawblock := &pcomm.Block{ 887 Header: &pcomm.BlockHeader{ 888 Number: uint64(1), 889 }, 890 Data: &pcomm.BlockData{ 891 Data: [][]byte{}, 892 }, 893 Metadata: &pcomm.BlockMetadata{ 894 Metadata: [][]byte{ 895 {}, {}, {}, {}, 896 }, 897 }, 898 } 899 b, _ := pb.Marshal(rawblock) 900 901 newMsg := func(channel string) *proto.GossipMessage { 902 { 903 return &proto.GossipMessage{ 904 Channel: []byte(channel), 905 Content: &proto.GossipMessage_DataMsg{ 906 DataMsg: &proto.DataMessage{ 907 Payload: &proto.Payload{ 908 SeqNum: 1, 909 Data: b, 910 }, 911 }, 912 }, 913 } 914 } 915 } 916 917 createChan := func(signalChan chan struct{}) <-chan *proto.GossipMessage { 918 c := make(chan *proto.GossipMessage) 919 920 go func(c chan *proto.GossipMessage) { 921 // Wait for Accept() to be called 922 <-signalChan 923 // Simulate a message reception from the gossip component with an invalid channel 924 c <- newMsg("AAA") 925 // Simulate a message reception from the gossip component 926 c <- newMsg("testchannelid") 927 }(c) 928 return c 929 } 930 931 g := &mocks.GossipMock{} 932 rmc := createChan(signalChan) 933 g.On("Accept", mock.Anything, false).Return(rmc, nil).Run(func(_ mock.Arguments) { 934 signalChan <- struct{}{} 935 }) 936 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 937 g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{}) 938 mc := &mockCommitter{Mock: &mock.Mock{}} 939 receivedChan := make(chan struct{}) 940 mc.On("CommitLegacy", mock.Anything).Run(func(arguments mock.Arguments) { 941 block := arguments.Get(0).(*pcomm.Block) 942 assert.Equal(t, uint64(1), block.Header.Number) 943 receivedChan <- struct{}{} 944 }) 945 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 946 mc.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 947 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 948 defer p.shutdown() 949 select { 950 case <-receivedChan: 951 case <-time.After(time.Second * 15): 952 assert.Fail(t, "Didn't commit a block within a timely manner") 953 } 954 } 955 956 func TestLedgerHeightFromProperties(t *testing.T) { 957 // Scenario: For each test, spawn a peer and supply it 958 // with a specific mock of PeersOfChannel from peers that 959 // either set both metadata properly, or only the properties, or none, or both. 960 // Ensure the logic handles all of the 4 possible cases as needed 961 962 // Returns whether the given networkMember was selected or not 963 wasNetworkMemberSelected := func(t *testing.T, networkMember discovery.NetworkMember) bool { 964 var wasGivenNetworkMemberSelected int32 965 finChan := make(chan struct{}) 966 g := &mocks.GossipMock{} 967 g.On("Send", mock.Anything, mock.Anything).Run(func(arguments mock.Arguments) { 968 msg := arguments.Get(0).(*proto.GossipMessage) 969 assert.NotNil(t, msg.GetStateRequest()) 970 peer := arguments.Get(1).([]*comm.RemotePeer)[0] 971 if bytes.Equal(networkMember.PKIid, peer.PKIID) { 972 atomic.StoreInt32(&wasGivenNetworkMemberSelected, 1) 973 } 974 finChan <- struct{}{} 975 }) 976 g.On("Accept", mock.Anything, false).Return(make(<-chan *proto.GossipMessage), nil) 977 g.On("Accept", mock.Anything, true).Return(nil, make(chan protoext.ReceivedMessage)) 978 defaultPeer := discovery.NetworkMember{ 979 InternalEndpoint: "b", 980 PKIid: common.PKIidType("b"), 981 Properties: &proto.Properties{ 982 LedgerHeight: 5, 983 }, 984 } 985 g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{ 986 defaultPeer, 987 networkMember, 988 }) 989 mc := &mockCommitter{Mock: &mock.Mock{}} 990 mc.On("LedgerHeight", mock.Anything).Return(uint64(1), nil) 991 p := newPeerNodeWithGossip(0, mc, noopPeerIdentityAcceptor, g) 992 defer p.shutdown() 993 select { 994 case <-time.After(time.Second * 20): 995 t.Fatal("Didn't send a request within a timely manner") 996 case <-finChan: 997 } 998 return atomic.LoadInt32(&wasGivenNetworkMemberSelected) == 1 999 } 1000 1001 peerWithProperties := discovery.NetworkMember{ 1002 PKIid: common.PKIidType("peerWithoutMetadata"), 1003 Properties: &proto.Properties{ 1004 LedgerHeight: 10, 1005 }, 1006 InternalEndpoint: "peerWithoutMetadata", 1007 } 1008 1009 peerWithoutProperties := discovery.NetworkMember{ 1010 PKIid: common.PKIidType("peerWithoutProperties"), 1011 InternalEndpoint: "peerWithoutProperties", 1012 } 1013 1014 tests := []struct { 1015 shouldGivenBeSelected bool 1016 member discovery.NetworkMember 1017 }{ 1018 {member: peerWithProperties, shouldGivenBeSelected: true}, 1019 {member: peerWithoutProperties, shouldGivenBeSelected: false}, 1020 } 1021 1022 for _, tst := range tests { 1023 assert.Equal(t, tst.shouldGivenBeSelected, wasNetworkMemberSelected(t, tst.member)) 1024 } 1025 } 1026 1027 func TestAccessControl(t *testing.T) { 1028 bootstrapSetSize := 5 1029 bootstrapSet := make([]*peerNode, 0) 1030 1031 authorizedPeersSize := 4 1032 var listeners []net.Listener 1033 var endpoints []string 1034 1035 for i := 0; i < authorizedPeersSize; i++ { 1036 ll, err := net.Listen("tcp", "127.0.0.1:0") 1037 assert.NoError(t, err) 1038 listeners = append(listeners, ll) 1039 endpoint := ll.Addr().String() 1040 endpoints = append(endpoints, endpoint) 1041 } 1042 1043 defer func() { 1044 for _, ll := range listeners { 1045 ll.Close() 1046 } 1047 }() 1048 1049 authorizedPeers := map[string]struct{}{ 1050 endpoints[0]: {}, 1051 endpoints[1]: {}, 1052 endpoints[2]: {}, 1053 endpoints[3]: {}, 1054 } 1055 1056 blockPullPolicy := func(identity api.PeerIdentityType) error { 1057 if _, isAuthorized := authorizedPeers[string(identity)]; isAuthorized { 1058 return nil 1059 } 1060 return errors.New("Not authorized") 1061 } 1062 1063 var bootPorts []int 1064 1065 for i := 0; i < bootstrapSetSize; i++ { 1066 commit := newCommitter() 1067 bootPeer, bootPort := newBootNode(i, commit, blockPullPolicy) 1068 bootstrapSet = append(bootstrapSet, bootPeer) 1069 bootPorts = append(bootPorts, bootPort) 1070 } 1071 1072 defer func() { 1073 for _, p := range bootstrapSet { 1074 p.shutdown() 1075 } 1076 }() 1077 1078 msgCount := 5 1079 1080 for i := 1; i <= msgCount; i++ { 1081 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 1082 if b, err := pb.Marshal(rawblock); err == nil { 1083 payload := &proto.Payload{ 1084 SeqNum: uint64(i), 1085 Data: b, 1086 } 1087 bootstrapSet[0].s.AddPayload(payload) 1088 } else { 1089 t.Fail() 1090 } 1091 } 1092 1093 standardPeerSetSize := 10 1094 peersSet := make([]*peerNode, 0) 1095 1096 for i := 0; i < standardPeerSetSize; i++ { 1097 commit := newCommitter() 1098 peersSet = append(peersSet, newPeerNode(bootstrapSetSize+i, commit, blockPullPolicy, bootPorts...)) 1099 } 1100 1101 defer func() { 1102 for _, p := range peersSet { 1103 p.shutdown() 1104 } 1105 }() 1106 1107 waitUntilTrueOrTimeout(t, func() bool { 1108 for _, p := range peersSet { 1109 if len(p.g.PeersOfChannel(common.ChannelID("testchannelid"))) != bootstrapSetSize+standardPeerSetSize-1 { 1110 t.Log("Peer discovery has not finished yet") 1111 return false 1112 } 1113 } 1114 t.Log("All peer discovered each other!!!") 1115 return true 1116 }, 30*time.Second) 1117 1118 t.Log("Waiting for all blocks to arrive.") 1119 waitUntilTrueOrTimeout(t, func() bool { 1120 t.Log("Trying to see all authorized peers get all blocks, and all non-authorized didn't") 1121 for _, p := range peersSet { 1122 height, err := p.commit.LedgerHeight() 1123 id := fmt.Sprintf("127.0.0.1:%d", p.port) 1124 if _, isAuthorized := authorizedPeers[id]; isAuthorized { 1125 if height != uint64(msgCount+1) || err != nil { 1126 return false 1127 } 1128 } else { 1129 if err == nil && height > 1 { 1130 assert.Fail(t, "Peer", id, "got message but isn't authorized! Height:", height) 1131 } 1132 } 1133 } 1134 t.Log("All peers have same ledger height!!!") 1135 return true 1136 }, 60*time.Second) 1137 } 1138 1139 func TestNewGossipStateProvider_SendingManyMessages(t *testing.T) { 1140 bootstrapSetSize := 5 1141 bootstrapSet := make([]*peerNode, 0) 1142 1143 var bootPorts []int 1144 1145 for i := 0; i < bootstrapSetSize; i++ { 1146 commit := newCommitter() 1147 bootPeer, bootPort := newBootNode(i, commit, noopPeerIdentityAcceptor) 1148 bootstrapSet = append(bootstrapSet, bootPeer) 1149 bootPorts = append(bootPorts, bootPort) 1150 } 1151 1152 defer func() { 1153 for _, p := range bootstrapSet { 1154 p.shutdown() 1155 } 1156 }() 1157 1158 msgCount := 10 1159 1160 for i := 1; i <= msgCount; i++ { 1161 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 1162 if b, err := pb.Marshal(rawblock); err == nil { 1163 payload := &proto.Payload{ 1164 SeqNum: uint64(i), 1165 Data: b, 1166 } 1167 bootstrapSet[0].s.AddPayload(payload) 1168 } else { 1169 t.Fail() 1170 } 1171 } 1172 1173 standartPeersSize := 10 1174 peersSet := make([]*peerNode, 0) 1175 1176 for i := 0; i < standartPeersSize; i++ { 1177 commit := newCommitter() 1178 peersSet = append(peersSet, newPeerNode(bootstrapSetSize+i, commit, noopPeerIdentityAcceptor, bootPorts...)) 1179 } 1180 1181 defer func() { 1182 for _, p := range peersSet { 1183 p.shutdown() 1184 } 1185 }() 1186 1187 waitUntilTrueOrTimeout(t, func() bool { 1188 for _, p := range peersSet { 1189 if len(p.g.PeersOfChannel(common.ChannelID("testchannelid"))) != bootstrapSetSize+standartPeersSize-1 { 1190 t.Log("Peer discovery has not finished yet") 1191 return false 1192 } 1193 } 1194 t.Log("All peer discovered each other!!!") 1195 return true 1196 }, 30*time.Second) 1197 1198 t.Log("Waiting for all blocks to arrive.") 1199 waitUntilTrueOrTimeout(t, func() bool { 1200 t.Log("Trying to see all peers get all blocks") 1201 for _, p := range peersSet { 1202 height, err := p.commit.LedgerHeight() 1203 if height != uint64(msgCount+1) || err != nil { 1204 return false 1205 } 1206 } 1207 t.Log("All peers have same ledger height!!!") 1208 return true 1209 }, 60*time.Second) 1210 } 1211 1212 // Start one bootstrap peer and submit defAntiEntropyBatchSize + 5 messages into 1213 // local ledger, next spawning a new peer waiting for anti-entropy procedure to 1214 // complete missing blocks. Since state transfer messages now batched, it is expected 1215 // to see _exactly_ two messages with state transfer response. 1216 func TestNewGossipStateProvider_BatchingOfStateRequest(t *testing.T) { 1217 bootPeer, bootPort := newBootNode(0, newCommitter(), noopPeerIdentityAcceptor) 1218 defer bootPeer.shutdown() 1219 1220 msgCount := defAntiEntropyBatchSize + 5 1221 expectedMessagesCnt := 2 1222 1223 for i := 1; i <= msgCount; i++ { 1224 rawblock := protoutil.NewBlock(uint64(i), []byte{}) 1225 if b, err := pb.Marshal(rawblock); err == nil { 1226 payload := &proto.Payload{ 1227 SeqNum: uint64(i), 1228 Data: b, 1229 } 1230 bootPeer.s.AddPayload(payload) 1231 } else { 1232 t.Fail() 1233 } 1234 } 1235 1236 peer := newPeerNode(1, newCommitter(), noopPeerIdentityAcceptor, bootPort) 1237 defer peer.shutdown() 1238 1239 naiveStateMsgPredicate := func(message interface{}) bool { 1240 return protoext.IsRemoteStateMessage(message.(protoext.ReceivedMessage).GetGossipMessage().GossipMessage) 1241 } 1242 _, peerCh := peer.g.Accept(naiveStateMsgPredicate, true) 1243 1244 wg := sync.WaitGroup{} 1245 wg.Add(expectedMessagesCnt) 1246 1247 // Number of submitted messages is defAntiEntropyBatchSize + 5, therefore 1248 // expected number of batches is expectedMessagesCnt = 2. Following go routine 1249 // makes sure it receives expected amount of messages and sends signal of success 1250 // to continue the test 1251 go func() { 1252 for count := 0; count < expectedMessagesCnt; count++ { 1253 <-peerCh 1254 wg.Done() 1255 } 1256 }() 1257 1258 // Once we got message which indicate of two batches being received, 1259 // making sure messages indeed committed. 1260 waitUntilTrueOrTimeout(t, func() bool { 1261 if len(peer.g.PeersOfChannel(common.ChannelID("testchannelid"))) != 1 { 1262 t.Log("Peer discovery has not finished yet") 1263 return false 1264 } 1265 t.Log("All peer discovered each other!!!") 1266 return true 1267 }, 30*time.Second) 1268 1269 // Waits for message which indicates that expected number of message batches received 1270 // otherwise timeouts after 2 * defAntiEntropyInterval + 1 seconds 1271 wg.Wait() 1272 1273 t.Log("Waiting for all blocks to arrive.") 1274 waitUntilTrueOrTimeout(t, func() bool { 1275 t.Log("Trying to see all peers get all blocks") 1276 height, err := peer.commit.LedgerHeight() 1277 if height != uint64(msgCount+1) || err != nil { 1278 return false 1279 } 1280 t.Log("All peers have same ledger height!!!") 1281 return true 1282 }, 60*time.Second) 1283 } 1284 1285 // coordinatorMock mocking structure to capture mock interface for 1286 // coord to simulate coord flow during the test 1287 type coordinatorMock struct { 1288 committer.Committer 1289 mock.Mock 1290 } 1291 1292 func (mock *coordinatorMock) GetPvtDataAndBlockByNum(seqNum uint64, _ protoutil.SignedData) (*pcomm.Block, gutil.PvtDataCollections, error) { 1293 args := mock.Called(seqNum) 1294 return args.Get(0).(*pcomm.Block), args.Get(1).(gutil.PvtDataCollections), args.Error(2) 1295 } 1296 1297 func (mock *coordinatorMock) GetBlockByNum(seqNum uint64) (*pcomm.Block, error) { 1298 args := mock.Called(seqNum) 1299 return args.Get(0).(*pcomm.Block), args.Error(1) 1300 } 1301 1302 func (mock *coordinatorMock) StoreBlock(block *pcomm.Block, data gutil.PvtDataCollections) error { 1303 args := mock.Called(block, data) 1304 return args.Error(1) 1305 } 1306 1307 func (mock *coordinatorMock) LedgerHeight() (uint64, error) { 1308 args := mock.Called() 1309 return args.Get(0).(uint64), args.Error(1) 1310 } 1311 1312 func (mock *coordinatorMock) Close() { 1313 mock.Called() 1314 } 1315 1316 // StorePvtData used to persist private date into transient store 1317 func (mock *coordinatorMock) StorePvtData(txid string, privData *tspb.TxPvtReadWriteSetWithConfigInfo, blkHeight uint64) error { 1318 return mock.Called().Error(0) 1319 } 1320 1321 type receivedMessageMock struct { 1322 mock.Mock 1323 } 1324 1325 // Ack returns to the sender an acknowledgement for the message 1326 func (mock *receivedMessageMock) Ack(err error) { 1327 1328 } 1329 1330 func (mock *receivedMessageMock) Respond(msg *proto.GossipMessage) { 1331 mock.Called(msg) 1332 } 1333 1334 func (mock *receivedMessageMock) GetGossipMessage() *protoext.SignedGossipMessage { 1335 args := mock.Called() 1336 return args.Get(0).(*protoext.SignedGossipMessage) 1337 } 1338 1339 func (mock *receivedMessageMock) GetSourceEnvelope() *proto.Envelope { 1340 args := mock.Called() 1341 return args.Get(0).(*proto.Envelope) 1342 } 1343 1344 func (mock *receivedMessageMock) GetConnectionInfo() *protoext.ConnectionInfo { 1345 args := mock.Called() 1346 return args.Get(0).(*protoext.ConnectionInfo) 1347 } 1348 1349 type testData struct { 1350 block *pcomm.Block 1351 pvtData gutil.PvtDataCollections 1352 } 1353 1354 func TestTransferOfPrivateRWSet(t *testing.T) { 1355 chainID := "testChainID" 1356 1357 // First gossip instance 1358 g := &mocks.GossipMock{} 1359 coord1 := new(coordinatorMock) 1360 1361 gossipChannel := make(chan *proto.GossipMessage) 1362 commChannel := make(chan protoext.ReceivedMessage) 1363 1364 gossipChannelFactory := func(ch chan *proto.GossipMessage) <-chan *proto.GossipMessage { 1365 return ch 1366 } 1367 1368 g.On("Accept", mock.Anything, false).Return(gossipChannelFactory(gossipChannel), nil) 1369 g.On("Accept", mock.Anything, true).Return(nil, commChannel) 1370 1371 g.On("UpdateChannelMetadata", mock.Anything, mock.Anything) 1372 g.On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{}) 1373 g.On("Close") 1374 1375 coord1.On("LedgerHeight", mock.Anything).Return(uint64(5), nil) 1376 1377 var data = map[uint64]*testData{ 1378 uint64(2): { 1379 block: &pcomm.Block{ 1380 Header: &pcomm.BlockHeader{ 1381 Number: 2, 1382 DataHash: []byte{0, 1, 1, 1}, 1383 PreviousHash: []byte{0, 0, 0, 1}, 1384 }, 1385 Data: &pcomm.BlockData{ 1386 Data: [][]byte{{1}, {2}, {3}}, 1387 }, 1388 }, 1389 pvtData: gutil.PvtDataCollections{ 1390 { 1391 SeqInBlock: uint64(0), 1392 WriteSet: &rwset.TxPvtReadWriteSet{ 1393 DataModel: rwset.TxReadWriteSet_KV, 1394 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1395 { 1396 Namespace: "myCC:v1", 1397 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 1398 { 1399 CollectionName: "mysecrectCollection", 1400 Rwset: []byte{1, 2, 3, 4, 5}, 1401 }, 1402 }, 1403 }, 1404 }, 1405 }, 1406 }, 1407 }, 1408 }, 1409 1410 uint64(3): { 1411 block: &pcomm.Block{ 1412 Header: &pcomm.BlockHeader{ 1413 Number: 3, 1414 DataHash: []byte{1, 1, 1, 1}, 1415 PreviousHash: []byte{0, 1, 1, 1}, 1416 }, 1417 Data: &pcomm.BlockData{ 1418 Data: [][]byte{{4}, {5}, {6}}, 1419 }, 1420 }, 1421 pvtData: gutil.PvtDataCollections{ 1422 { 1423 SeqInBlock: uint64(2), 1424 WriteSet: &rwset.TxPvtReadWriteSet{ 1425 DataModel: rwset.TxReadWriteSet_KV, 1426 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1427 { 1428 Namespace: "otherCC:v1", 1429 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 1430 { 1431 CollectionName: "topClassified", 1432 Rwset: []byte{0, 0, 0, 4, 2}, 1433 }, 1434 }, 1435 }, 1436 }, 1437 }, 1438 }, 1439 }, 1440 }, 1441 } 1442 1443 for seqNum, each := range data { 1444 coord1.On("GetPvtDataAndBlockByNum", seqNum).Return(each.block, each.pvtData, nil /* no error*/) 1445 } 1446 1447 coord1.On("Close") 1448 1449 servicesAdapater := &ServicesMediator{GossipAdapter: g, MCSAdapter: &cryptoServiceMock{acceptor: noopPeerIdentityAcceptor}} 1450 stateMetrics := metrics.NewGossipMetrics(&disabled.Provider{}).StateMetrics 1451 stateConfig := &StateConfig{ 1452 StateCheckInterval: DefStateCheckInterval, 1453 StateResponseTimeout: DefStateResponseTimeout, 1454 StateBatchSize: DefStateBatchSize, 1455 StateMaxRetries: DefStateMaxRetries, 1456 StateBlockBufferSize: DefStateBlockBufferSize, 1457 StateChannelSize: DefStateChannelSize, 1458 StateEnabled: true, 1459 } 1460 logger := flogging.MustGetLogger(gutil.StateLogger) 1461 st := NewGossipStateProvider(logger, chainID, servicesAdapater, coord1, stateMetrics, blocking, stateConfig) 1462 defer st.Stop() 1463 1464 // Mocked state request message 1465 requestMsg := new(receivedMessageMock) 1466 1467 // Get state request message, blocks [2...3] 1468 requestGossipMsg := &proto.GossipMessage{ 1469 // Copy nonce field from the request, so it will be possible to match response 1470 Nonce: 1, 1471 Tag: proto.GossipMessage_CHAN_OR_ORG, 1472 Channel: []byte(chainID), 1473 Content: &proto.GossipMessage_StateRequest{StateRequest: &proto.RemoteStateRequest{ 1474 StartSeqNum: 2, 1475 EndSeqNum: 3, 1476 }}, 1477 } 1478 1479 msg, _ := protoext.NoopSign(requestGossipMsg) 1480 1481 requestMsg.On("GetGossipMessage").Return(msg) 1482 requestMsg.On("GetConnectionInfo").Return(&protoext.ConnectionInfo{ 1483 Auth: &protoext.AuthInfo{}, 1484 }) 1485 1486 // Channel to send responses back 1487 responseChannel := make(chan protoext.ReceivedMessage) 1488 defer close(responseChannel) 1489 1490 requestMsg.On("Respond", mock.Anything).Run(func(args mock.Arguments) { 1491 // Get gossip response to respond back on state request 1492 response := args.Get(0).(*proto.GossipMessage) 1493 // Wrap it up into received response 1494 receivedMsg := new(receivedMessageMock) 1495 // Create sign response 1496 msg, _ := protoext.NoopSign(response) 1497 // Mock to respond 1498 receivedMsg.On("GetGossipMessage").Return(msg) 1499 // Send response 1500 responseChannel <- receivedMsg 1501 }) 1502 1503 // Send request message via communication channel into state transfer 1504 commChannel <- requestMsg 1505 1506 // State transfer request should result in state response back 1507 response := <-responseChannel 1508 1509 // Start the assertion section 1510 stateResponse := response.GetGossipMessage().GetStateResponse() 1511 1512 assertion := assert.New(t) 1513 // Nonce should be equal to Nonce of the request 1514 assertion.Equal(response.GetGossipMessage().Nonce, uint64(1)) 1515 // Payload should not need be nil 1516 assertion.NotNil(stateResponse) 1517 assertion.NotNil(stateResponse.Payloads) 1518 // Exactly two messages expected 1519 assertion.Equal(len(stateResponse.Payloads), 2) 1520 1521 // Assert we have all data and it's same as we expected it 1522 for _, each := range stateResponse.Payloads { 1523 block := &pcomm.Block{} 1524 err := pb.Unmarshal(each.Data, block) 1525 assertion.NoError(err) 1526 1527 assertion.NotNil(block.Header) 1528 1529 testBlock, ok := data[block.Header.Number] 1530 assertion.True(ok) 1531 1532 for i, d := range testBlock.block.Data.Data { 1533 assertion.True(bytes.Equal(d, block.Data.Data[i])) 1534 } 1535 1536 for i, p := range testBlock.pvtData { 1537 pvtDataPayload := &proto.PvtDataPayload{} 1538 err := pb.Unmarshal(each.PrivateData[i], pvtDataPayload) 1539 assertion.NoError(err) 1540 pvtRWSet := &rwset.TxPvtReadWriteSet{} 1541 err = pb.Unmarshal(pvtDataPayload.Payload, pvtRWSet) 1542 assertion.NoError(err) 1543 assertion.True(pb.Equal(p.WriteSet, pvtRWSet)) 1544 } 1545 } 1546 } 1547 1548 type testPeer struct { 1549 *mocks.GossipMock 1550 id string 1551 gossipChannel chan *proto.GossipMessage 1552 commChannel chan protoext.ReceivedMessage 1553 coord *coordinatorMock 1554 } 1555 1556 func (t testPeer) Gossip() <-chan *proto.GossipMessage { 1557 return t.gossipChannel 1558 } 1559 1560 func (t testPeer) Comm() chan protoext.ReceivedMessage { 1561 return t.commChannel 1562 } 1563 1564 var peers = map[string]testPeer{ 1565 "peer1": { 1566 id: "peer1", 1567 gossipChannel: make(chan *proto.GossipMessage), 1568 commChannel: make(chan protoext.ReceivedMessage), 1569 GossipMock: &mocks.GossipMock{}, 1570 coord: new(coordinatorMock), 1571 }, 1572 "peer2": { 1573 id: "peer2", 1574 gossipChannel: make(chan *proto.GossipMessage), 1575 commChannel: make(chan protoext.ReceivedMessage), 1576 GossipMock: &mocks.GossipMock{}, 1577 coord: new(coordinatorMock), 1578 }, 1579 } 1580 1581 func TestTransferOfPvtDataBetweenPeers(t *testing.T) { 1582 /* 1583 This test covers pretty basic scenario, there are two peers: "peer1" and "peer2", 1584 while peer2 missing a few blocks in the ledger therefore asking to replicate those 1585 blocks from the first peers. 1586 1587 Test going to check that block from one peer will be replicated into second one and 1588 have identical content. 1589 */ 1590 chainID := "testChainID" 1591 1592 // Initialize peer 1593 for _, peer := range peers { 1594 peer.On("Accept", mock.Anything, false).Return(peer.Gossip(), nil) 1595 1596 peer.On("Accept", mock.Anything, true). 1597 Return(nil, peer.Comm()). 1598 Once(). 1599 On("Accept", mock.Anything, true). 1600 Return(nil, make(chan protoext.ReceivedMessage)) 1601 1602 peer.On("UpdateChannelMetadata", mock.Anything, mock.Anything) 1603 peer.coord.On("Close") 1604 peer.On("Close") 1605 } 1606 1607 // First peer going to have more advanced ledger 1608 peers["peer1"].coord.On("LedgerHeight", mock.Anything).Return(uint64(3), nil) 1609 1610 // Second peer has a gap of one block, hence it will have to replicate it from previous 1611 peers["peer2"].coord.On("LedgerHeight", mock.Anything).Return(uint64(2), nil) 1612 1613 peers["peer1"].coord.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 1614 peers["peer2"].coord.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil) 1615 1616 peers["peer1"].coord.On("GetPvtDataAndBlockByNum", uint64(2)).Return(&pcomm.Block{ 1617 Header: &pcomm.BlockHeader{ 1618 Number: 2, 1619 DataHash: []byte{0, 0, 0, 1}, 1620 PreviousHash: []byte{0, 1, 1, 1}, 1621 }, 1622 Data: &pcomm.BlockData{ 1623 Data: [][]byte{{4}, {5}, {6}}, 1624 }, 1625 }, gutil.PvtDataCollections{&ledger.TxPvtData{ 1626 SeqInBlock: uint64(1), 1627 WriteSet: &rwset.TxPvtReadWriteSet{ 1628 DataModel: rwset.TxReadWriteSet_KV, 1629 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1630 { 1631 Namespace: "myCC:v1", 1632 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 1633 { 1634 CollectionName: "mysecrectCollection", 1635 Rwset: []byte{1, 2, 3, 4, 5}, 1636 }, 1637 }, 1638 }, 1639 }, 1640 }, 1641 }}, nil) 1642 1643 // Return membership of the peers 1644 member2 := discovery.NetworkMember{ 1645 PKIid: common.PKIidType([]byte{2}), 1646 Endpoint: "peer2:7051", 1647 InternalEndpoint: "peer2:7051", 1648 Properties: &proto.Properties{ 1649 LedgerHeight: 2, 1650 }, 1651 } 1652 1653 member1 := discovery.NetworkMember{ 1654 PKIid: common.PKIidType([]byte{1}), 1655 Endpoint: "peer1:7051", 1656 InternalEndpoint: "peer1:7051", 1657 Properties: &proto.Properties{ 1658 LedgerHeight: 3, 1659 }, 1660 } 1661 1662 peers["peer1"].On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{member2}) 1663 peers["peer2"].On("PeersOfChannel", mock.Anything).Return([]discovery.NetworkMember{member1}) 1664 1665 peers["peer2"].On("Send", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { 1666 request := args.Get(0).(*proto.GossipMessage) 1667 requestMsg := new(receivedMessageMock) 1668 msg, _ := protoext.NoopSign(request) 1669 requestMsg.On("GetGossipMessage").Return(msg) 1670 requestMsg.On("GetConnectionInfo").Return(&protoext.ConnectionInfo{ 1671 Auth: &protoext.AuthInfo{}, 1672 }) 1673 1674 requestMsg.On("Respond", mock.Anything).Run(func(args mock.Arguments) { 1675 response := args.Get(0).(*proto.GossipMessage) 1676 receivedMsg := new(receivedMessageMock) 1677 msg, _ := protoext.NoopSign(response) 1678 receivedMsg.On("GetGossipMessage").Return(msg) 1679 // Send response back to the peer 1680 peers["peer2"].commChannel <- receivedMsg 1681 }) 1682 1683 peers["peer1"].commChannel <- requestMsg 1684 }) 1685 1686 wg := sync.WaitGroup{} 1687 wg.Add(1) 1688 peers["peer2"].coord.On("StoreBlock", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { 1689 wg.Done() // Done once second peer hits commit of the block 1690 }).Return([]string{}, nil) // No pvt data to complete and no error 1691 1692 cryptoService := &cryptoServiceMock{acceptor: noopPeerIdentityAcceptor} 1693 1694 stateMetrics := metrics.NewGossipMetrics(&disabled.Provider{}).StateMetrics 1695 1696 mediator := &ServicesMediator{GossipAdapter: peers["peer1"], MCSAdapter: cryptoService} 1697 stateConfig := &StateConfig{ 1698 StateCheckInterval: DefStateCheckInterval, 1699 StateResponseTimeout: DefStateResponseTimeout, 1700 StateBatchSize: DefStateBatchSize, 1701 StateMaxRetries: DefStateMaxRetries, 1702 StateBlockBufferSize: DefStateBlockBufferSize, 1703 StateChannelSize: DefStateChannelSize, 1704 StateEnabled: true, 1705 } 1706 logger := flogging.MustGetLogger(gutil.StateLogger) 1707 peer1State := NewGossipStateProvider(logger, chainID, mediator, peers["peer1"].coord, stateMetrics, blocking, stateConfig) 1708 defer peer1State.Stop() 1709 1710 mediator = &ServicesMediator{GossipAdapter: peers["peer2"], MCSAdapter: cryptoService} 1711 logger = flogging.MustGetLogger(gutil.StateLogger) 1712 peer2State := NewGossipStateProvider(logger, chainID, mediator, peers["peer2"].coord, stateMetrics, blocking, stateConfig) 1713 defer peer2State.Stop() 1714 1715 // Make sure state was replicated 1716 done := make(chan struct{}) 1717 go func() { 1718 wg.Wait() 1719 done <- struct{}{} 1720 }() 1721 1722 select { 1723 case <-done: 1724 break 1725 case <-time.After(30 * time.Second): 1726 t.Fail() 1727 } 1728 } 1729 1730 func TestStateRequestValidator(t *testing.T) { 1731 validator := &stateRequestValidator{} 1732 err := validator.validate(&proto.RemoteStateRequest{ 1733 StartSeqNum: 10, 1734 EndSeqNum: 5, 1735 }, defAntiEntropyBatchSize) 1736 assert.Contains(t, err.Error(), "Invalid sequence interval [10...5).") 1737 assert.Error(t, err) 1738 1739 err = validator.validate(&proto.RemoteStateRequest{ 1740 StartSeqNum: 10, 1741 EndSeqNum: 30, 1742 }, defAntiEntropyBatchSize) 1743 assert.Contains(t, err.Error(), "Requesting blocks range [10-30) greater than configured") 1744 assert.Error(t, err) 1745 1746 err = validator.validate(&proto.RemoteStateRequest{ 1747 StartSeqNum: 10, 1748 EndSeqNum: 20, 1749 }, defAntiEntropyBatchSize) 1750 assert.NoError(t, err) 1751 } 1752 1753 func waitUntilTrueOrTimeout(t *testing.T, predicate func() bool, timeout time.Duration) { 1754 ch := make(chan struct{}) 1755 t.Log("Started to spin off, until predicate will be satisfied.") 1756 1757 go func() { 1758 t := time.NewTicker(time.Second) 1759 for !predicate() { 1760 select { 1761 case <-ch: 1762 t.Stop() 1763 return 1764 case <-t.C: 1765 } 1766 } 1767 t.Stop() 1768 close(ch) 1769 }() 1770 1771 select { 1772 case <-ch: 1773 t.Log("Done.") 1774 break 1775 case <-time.After(timeout): 1776 t.Fatal("Timeout has expired") 1777 close(ch) 1778 break 1779 } 1780 t.Log("Stop waiting until timeout or true") 1781 }