github.com/516108736/tendermint@v0.36.0/consensus/common_test.go (about) 1 package consensus 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "sort" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/go-kit/kit/log/term" 16 "github.com/stretchr/testify/require" 17 18 "path" 19 20 dbm "github.com/tendermint/tm-db" 21 22 abcicli "github.com/tendermint/tendermint/abci/client" 23 "github.com/tendermint/tendermint/abci/example/counter" 24 "github.com/tendermint/tendermint/abci/example/kvstore" 25 abci "github.com/tendermint/tendermint/abci/types" 26 cfg "github.com/tendermint/tendermint/config" 27 cstypes "github.com/tendermint/tendermint/consensus/types" 28 tmbytes "github.com/tendermint/tendermint/libs/bytes" 29 "github.com/tendermint/tendermint/libs/log" 30 tmos "github.com/tendermint/tendermint/libs/os" 31 tmpubsub "github.com/tendermint/tendermint/libs/pubsub" 32 tmsync "github.com/tendermint/tendermint/libs/sync" 33 mempl "github.com/tendermint/tendermint/mempool" 34 "github.com/tendermint/tendermint/p2p" 35 "github.com/tendermint/tendermint/privval" 36 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 37 sm "github.com/tendermint/tendermint/state" 38 "github.com/tendermint/tendermint/store" 39 "github.com/tendermint/tendermint/types" 40 tmtime "github.com/tendermint/tendermint/types/time" 41 ) 42 43 const ( 44 testSubscriber = "test-client" 45 ) 46 47 // A cleanupFunc cleans up any config / test files created for a particular 48 // test. 49 type cleanupFunc func() 50 51 // genesis, chain_id, priv_val 52 var ( 53 config *cfg.Config // NOTE: must be reset for each _test.go file 54 consensusReplayConfig *cfg.Config 55 ensureTimeout = time.Millisecond * 200 56 ) 57 58 func ensureDir(dir string, mode os.FileMode) { 59 if err := tmos.EnsureDir(dir, mode); err != nil { 60 panic(err) 61 } 62 } 63 64 func ResetConfig(name string) *cfg.Config { 65 return cfg.ResetTestRoot(name) 66 } 67 68 //------------------------------------------------------------------------------- 69 // validator stub (a kvstore consensus peer we control) 70 71 type validatorStub struct { 72 Index int32 // Validator index. NOTE: we don't assume validator set changes. 73 Height int64 74 Round int32 75 types.PrivValidator 76 VotingPower int64 77 } 78 79 var testMinPower int64 = 10 80 81 func newValidatorStub(privValidator types.PrivValidator, valIndex int32) *validatorStub { 82 return &validatorStub{ 83 Index: valIndex, 84 PrivValidator: privValidator, 85 VotingPower: testMinPower, 86 } 87 } 88 89 func (vs *validatorStub) signVote( 90 voteType tmproto.SignedMsgType, 91 hash []byte, 92 header types.PartSetHeader) (*types.Vote, error) { 93 94 pubKey, err := vs.PrivValidator.GetPubKey() 95 if err != nil { 96 return nil, fmt.Errorf("can't get pubkey: %w", err) 97 } 98 99 vote := &types.Vote{ 100 ValidatorIndex: vs.Index, 101 ValidatorAddress: pubKey.Address(), 102 Height: vs.Height, 103 Round: vs.Round, 104 Timestamp: tmtime.Now(), 105 Type: voteType, 106 BlockID: types.BlockID{Hash: hash, PartSetHeader: header}, 107 } 108 v := vote.ToProto() 109 err = vs.PrivValidator.SignVote(config.ChainID(), v) 110 vote.Signature = v.Signature 111 112 return vote, err 113 } 114 115 // Sign vote for type/hash/header 116 func signVote(vs *validatorStub, voteType tmproto.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote { 117 v, err := vs.signVote(voteType, hash, header) 118 if err != nil { 119 panic(fmt.Errorf("failed to sign vote: %v", err)) 120 } 121 return v 122 } 123 124 func signVotes( 125 voteType tmproto.SignedMsgType, 126 hash []byte, 127 header types.PartSetHeader, 128 vss ...*validatorStub) []*types.Vote { 129 votes := make([]*types.Vote, len(vss)) 130 for i, vs := range vss { 131 votes[i] = signVote(vs, voteType, hash, header) 132 } 133 return votes 134 } 135 136 func incrementHeight(vss ...*validatorStub) { 137 for _, vs := range vss { 138 vs.Height++ 139 } 140 } 141 142 func incrementRound(vss ...*validatorStub) { 143 for _, vs := range vss { 144 vs.Round++ 145 } 146 } 147 148 type ValidatorStubsByPower []*validatorStub 149 150 func (vss ValidatorStubsByPower) Len() int { 151 return len(vss) 152 } 153 154 func (vss ValidatorStubsByPower) Less(i, j int) bool { 155 vssi, err := vss[i].GetPubKey() 156 if err != nil { 157 panic(err) 158 } 159 vssj, err := vss[j].GetPubKey() 160 if err != nil { 161 panic(err) 162 } 163 164 if vss[i].VotingPower == vss[j].VotingPower { 165 return bytes.Compare(vssi.Address(), vssj.Address()) == -1 166 } 167 return vss[i].VotingPower > vss[j].VotingPower 168 } 169 170 func (vss ValidatorStubsByPower) Swap(i, j int) { 171 it := vss[i] 172 vss[i] = vss[j] 173 vss[i].Index = int32(i) 174 vss[j] = it 175 vss[j].Index = int32(j) 176 } 177 178 //------------------------------------------------------------------------------- 179 // Functions for transitioning the consensus state 180 181 func startTestRound(cs *State, height int64, round int32) { 182 cs.enterNewRound(height, round) 183 cs.startRoutines(0) 184 } 185 186 // Create proposal block from cs1 but sign it with vs. 187 func decideProposal( 188 cs1 *State, 189 vs *validatorStub, 190 height int64, 191 round int32, 192 ) (proposal *types.Proposal, block *types.Block) { 193 cs1.mtx.Lock() 194 block, blockParts := cs1.createProposalBlock() 195 validRound := cs1.ValidRound 196 chainID := cs1.state.ChainID 197 cs1.mtx.Unlock() 198 if block == nil { 199 panic("Failed to createProposalBlock. Did you forget to add commit for previous block?") 200 } 201 202 // Make proposal 203 polRound, propBlockID := validRound, types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()} 204 proposal = types.NewProposal(height, round, polRound, propBlockID) 205 p := proposal.ToProto() 206 if err := vs.SignProposal(chainID, p); err != nil { 207 panic(err) 208 } 209 210 proposal.Signature = p.Signature 211 212 return 213 } 214 215 func addVotes(to *State, votes ...*types.Vote) { 216 for _, vote := range votes { 217 to.peerMsgQueue <- msgInfo{Msg: &VoteMessage{vote}} 218 } 219 } 220 221 func signAddVotes( 222 to *State, 223 voteType tmproto.SignedMsgType, 224 hash []byte, 225 header types.PartSetHeader, 226 vss ...*validatorStub, 227 ) { 228 votes := signVotes(voteType, hash, header, vss...) 229 addVotes(to, votes...) 230 } 231 232 func validatePrevote(t *testing.T, cs *State, round int32, privVal *validatorStub, blockHash []byte) { 233 prevotes := cs.Votes.Prevotes(round) 234 pubKey, err := privVal.GetPubKey() 235 require.NoError(t, err) 236 address := pubKey.Address() 237 var vote *types.Vote 238 if vote = prevotes.GetByAddress(address); vote == nil { 239 panic("Failed to find prevote from validator") 240 } 241 if blockHash == nil { 242 if vote.BlockID.Hash != nil { 243 panic(fmt.Sprintf("Expected prevote to be for nil, got %X", vote.BlockID.Hash)) 244 } 245 } else { 246 if !bytes.Equal(vote.BlockID.Hash, blockHash) { 247 panic(fmt.Sprintf("Expected prevote to be for %X, got %X", blockHash, vote.BlockID.Hash)) 248 } 249 } 250 } 251 252 func validateLastPrecommit(t *testing.T, cs *State, privVal *validatorStub, blockHash []byte) { 253 votes := cs.LastCommit 254 pv, err := privVal.GetPubKey() 255 require.NoError(t, err) 256 address := pv.Address() 257 var vote *types.Vote 258 if vote = votes.GetByAddress(address); vote == nil { 259 panic("Failed to find precommit from validator") 260 } 261 if !bytes.Equal(vote.BlockID.Hash, blockHash) { 262 panic(fmt.Sprintf("Expected precommit to be for %X, got %X", blockHash, vote.BlockID.Hash)) 263 } 264 } 265 266 func validatePrecommit( 267 t *testing.T, 268 cs *State, 269 thisRound, 270 lockRound int32, 271 privVal *validatorStub, 272 votedBlockHash, 273 lockedBlockHash []byte, 274 ) { 275 precommits := cs.Votes.Precommits(thisRound) 276 pv, err := privVal.GetPubKey() 277 require.NoError(t, err) 278 address := pv.Address() 279 var vote *types.Vote 280 if vote = precommits.GetByAddress(address); vote == nil { 281 panic("Failed to find precommit from validator") 282 } 283 284 if votedBlockHash == nil { 285 if vote.BlockID.Hash != nil { 286 panic("Expected precommit to be for nil") 287 } 288 } else { 289 if !bytes.Equal(vote.BlockID.Hash, votedBlockHash) { 290 panic("Expected precommit to be for proposal block") 291 } 292 } 293 294 if lockedBlockHash == nil { 295 if cs.LockedRound != lockRound || cs.LockedBlock != nil { 296 panic(fmt.Sprintf( 297 "Expected to be locked on nil at round %d. Got locked at round %d with block %v", 298 lockRound, 299 cs.LockedRound, 300 cs.LockedBlock)) 301 } 302 } else { 303 if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) { 304 panic(fmt.Sprintf( 305 "Expected block to be locked on round %d, got %d. Got locked block %X, expected %X", 306 lockRound, 307 cs.LockedRound, 308 cs.LockedBlock.Hash(), 309 lockedBlockHash)) 310 } 311 } 312 } 313 314 func validatePrevoteAndPrecommit( 315 t *testing.T, 316 cs *State, 317 thisRound, 318 lockRound int32, 319 privVal *validatorStub, 320 votedBlockHash, 321 lockedBlockHash []byte, 322 ) { 323 // verify the prevote 324 validatePrevote(t, cs, thisRound, privVal, votedBlockHash) 325 // verify precommit 326 cs.mtx.Lock() 327 validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash) 328 cs.mtx.Unlock() 329 } 330 331 func subscribeToVoter(cs *State, addr []byte) <-chan tmpubsub.Message { 332 votesSub, err := cs.eventBus.SubscribeUnbuffered(context.Background(), testSubscriber, types.EventQueryVote) 333 if err != nil { 334 panic(fmt.Sprintf("failed to subscribe %s to %v", testSubscriber, types.EventQueryVote)) 335 } 336 ch := make(chan tmpubsub.Message) 337 go func() { 338 for msg := range votesSub.Out() { 339 vote := msg.Data().(types.EventDataVote) 340 // we only fire for our own votes 341 if bytes.Equal(addr, vote.Vote.ValidatorAddress) { 342 ch <- msg 343 } 344 } 345 }() 346 return ch 347 } 348 349 //------------------------------------------------------------------------------- 350 // consensus states 351 352 func newState(state sm.State, pv types.PrivValidator, app abci.Application) *State { 353 config := cfg.ResetTestRoot("consensus_state_test") 354 return newStateWithConfig(config, state, pv, app) 355 } 356 357 func newStateWithConfig( 358 thisConfig *cfg.Config, 359 state sm.State, 360 pv types.PrivValidator, 361 app abci.Application, 362 ) *State { 363 blockDB := dbm.NewMemDB() 364 return newStateWithConfigAndBlockStore(thisConfig, state, pv, app, blockDB) 365 } 366 367 func newStateWithConfigAndBlockStore( 368 thisConfig *cfg.Config, 369 state sm.State, 370 pv types.PrivValidator, 371 app abci.Application, 372 blockDB dbm.DB, 373 ) *State { 374 // Get BlockStore 375 blockStore := store.NewBlockStore(blockDB) 376 377 // one for mempool, one for consensus 378 mtx := new(tmsync.Mutex) 379 proxyAppConnMem := abcicli.NewLocalClient(mtx, app) 380 proxyAppConnCon := abcicli.NewLocalClient(mtx, app) 381 382 // Make Mempool 383 mempool := mempl.NewCListMempool(thisConfig.Mempool, proxyAppConnMem, 0) 384 mempool.SetLogger(log.TestingLogger().With("module", "mempool")) 385 if thisConfig.Consensus.WaitForTxs() { 386 mempool.EnableTxsAvailable() 387 } 388 389 evpool := sm.EmptyEvidencePool{} 390 391 // Make State 392 stateDB := blockDB 393 stateStore := sm.NewStore(stateDB) 394 if err := stateStore.Save(state); err != nil { // for save height 1's validators info 395 panic(err) 396 } 397 398 blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool) 399 cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool) 400 cs.SetLogger(log.TestingLogger().With("module", "consensus")) 401 cs.SetPrivValidator(pv) 402 403 eventBus := types.NewEventBus() 404 eventBus.SetLogger(log.TestingLogger().With("module", "events")) 405 err := eventBus.Start() 406 if err != nil { 407 panic(err) 408 } 409 cs.SetEventBus(eventBus) 410 return cs 411 } 412 413 func loadPrivValidator(config *cfg.Config) *privval.FilePV { 414 privValidatorKeyFile := config.PrivValidatorKeyFile() 415 ensureDir(filepath.Dir(privValidatorKeyFile), 0700) 416 privValidatorStateFile := config.PrivValidatorStateFile() 417 privValidator := privval.LoadOrGenFilePV(privValidatorKeyFile, privValidatorStateFile) 418 privValidator.Reset() 419 return privValidator 420 } 421 422 func randState(nValidators int) (*State, []*validatorStub) { 423 // Get State 424 state, privVals := randGenesisState(nValidators, false, 10) 425 426 vss := make([]*validatorStub, nValidators) 427 428 cs := newState(state, privVals[0], counter.NewApplication(true)) 429 430 for i := 0; i < nValidators; i++ { 431 vss[i] = newValidatorStub(privVals[i], int32(i)) 432 } 433 // since cs1 starts at 1 434 incrementHeight(vss[1:]...) 435 436 return cs, vss 437 } 438 439 //------------------------------------------------------------------------------- 440 441 func ensureNoNewEvent(ch <-chan tmpubsub.Message, timeout time.Duration, 442 errorMessage string) { 443 select { 444 case <-time.After(timeout): 445 break 446 case <-ch: 447 panic(errorMessage) 448 } 449 } 450 451 func ensureNoNewEventOnChannel(ch <-chan tmpubsub.Message) { 452 ensureNoNewEvent( 453 ch, 454 ensureTimeout, 455 "We should be stuck waiting, not receiving new event on the channel") 456 } 457 458 func ensureNoNewRoundStep(stepCh <-chan tmpubsub.Message) { 459 ensureNoNewEvent( 460 stepCh, 461 ensureTimeout, 462 "We should be stuck waiting, not receiving NewRoundStep event") 463 } 464 465 func ensureNoNewUnlock(unlockCh <-chan tmpubsub.Message) { 466 ensureNoNewEvent( 467 unlockCh, 468 ensureTimeout, 469 "We should be stuck waiting, not receiving Unlock event") 470 } 471 472 func ensureNoNewTimeout(stepCh <-chan tmpubsub.Message, timeout int64) { 473 timeoutDuration := time.Duration(timeout*10) * time.Nanosecond 474 ensureNoNewEvent( 475 stepCh, 476 timeoutDuration, 477 "We should be stuck waiting, not receiving NewTimeout event") 478 } 479 480 func ensureNewEvent(ch <-chan tmpubsub.Message, height int64, round int32, timeout time.Duration, errorMessage string) { 481 select { 482 case <-time.After(timeout): 483 panic(errorMessage) 484 case msg := <-ch: 485 roundStateEvent, ok := msg.Data().(types.EventDataRoundState) 486 if !ok { 487 panic(fmt.Sprintf("expected a EventDataRoundState, got %T. Wrong subscription channel?", 488 msg.Data())) 489 } 490 if roundStateEvent.Height != height { 491 panic(fmt.Sprintf("expected height %v, got %v", height, roundStateEvent.Height)) 492 } 493 if roundStateEvent.Round != round { 494 panic(fmt.Sprintf("expected round %v, got %v", round, roundStateEvent.Round)) 495 } 496 // TODO: We could check also for a step at this point! 497 } 498 } 499 500 func ensureNewRound(roundCh <-chan tmpubsub.Message, height int64, round int32) { 501 select { 502 case <-time.After(ensureTimeout): 503 panic("Timeout expired while waiting for NewRound event") 504 case msg := <-roundCh: 505 newRoundEvent, ok := msg.Data().(types.EventDataNewRound) 506 if !ok { 507 panic(fmt.Sprintf("expected a EventDataNewRound, got %T. Wrong subscription channel?", 508 msg.Data())) 509 } 510 if newRoundEvent.Height != height { 511 panic(fmt.Sprintf("expected height %v, got %v", height, newRoundEvent.Height)) 512 } 513 if newRoundEvent.Round != round { 514 panic(fmt.Sprintf("expected round %v, got %v", round, newRoundEvent.Round)) 515 } 516 } 517 } 518 519 func ensureNewTimeout(timeoutCh <-chan tmpubsub.Message, height int64, round int32, timeout int64) { 520 timeoutDuration := time.Duration(timeout*10) * time.Nanosecond 521 ensureNewEvent(timeoutCh, height, round, timeoutDuration, 522 "Timeout expired while waiting for NewTimeout event") 523 } 524 525 func ensureNewProposal(proposalCh <-chan tmpubsub.Message, height int64, round int32) { 526 select { 527 case <-time.After(ensureTimeout): 528 panic("Timeout expired while waiting for NewProposal event") 529 case msg := <-proposalCh: 530 proposalEvent, ok := msg.Data().(types.EventDataCompleteProposal) 531 if !ok { 532 panic(fmt.Sprintf("expected a EventDataCompleteProposal, got %T. Wrong subscription channel?", 533 msg.Data())) 534 } 535 if proposalEvent.Height != height { 536 panic(fmt.Sprintf("expected height %v, got %v", height, proposalEvent.Height)) 537 } 538 if proposalEvent.Round != round { 539 panic(fmt.Sprintf("expected round %v, got %v", round, proposalEvent.Round)) 540 } 541 } 542 } 543 544 func ensureNewValidBlock(validBlockCh <-chan tmpubsub.Message, height int64, round int32) { 545 ensureNewEvent(validBlockCh, height, round, ensureTimeout, 546 "Timeout expired while waiting for NewValidBlock event") 547 } 548 549 func ensureNewBlock(blockCh <-chan tmpubsub.Message, height int64) { 550 select { 551 case <-time.After(ensureTimeout): 552 panic("Timeout expired while waiting for NewBlock event") 553 case msg := <-blockCh: 554 blockEvent, ok := msg.Data().(types.EventDataNewBlock) 555 if !ok { 556 panic(fmt.Sprintf("expected a EventDataNewBlock, got %T. Wrong subscription channel?", 557 msg.Data())) 558 } 559 if blockEvent.Block.Height != height { 560 panic(fmt.Sprintf("expected height %v, got %v", height, blockEvent.Block.Height)) 561 } 562 } 563 } 564 565 func ensureNewBlockHeader(blockCh <-chan tmpubsub.Message, height int64, blockHash tmbytes.HexBytes) { 566 select { 567 case <-time.After(ensureTimeout): 568 panic("Timeout expired while waiting for NewBlockHeader event") 569 case msg := <-blockCh: 570 blockHeaderEvent, ok := msg.Data().(types.EventDataNewBlockHeader) 571 if !ok { 572 panic(fmt.Sprintf("expected a EventDataNewBlockHeader, got %T. Wrong subscription channel?", 573 msg.Data())) 574 } 575 if blockHeaderEvent.Header.Height != height { 576 panic(fmt.Sprintf("expected height %v, got %v", height, blockHeaderEvent.Header.Height)) 577 } 578 if !bytes.Equal(blockHeaderEvent.Header.Hash(), blockHash) { 579 panic(fmt.Sprintf("expected header %X, got %X", blockHash, blockHeaderEvent.Header.Hash())) 580 } 581 } 582 } 583 584 func ensureNewUnlock(unlockCh <-chan tmpubsub.Message, height int64, round int32) { 585 ensureNewEvent(unlockCh, height, round, ensureTimeout, 586 "Timeout expired while waiting for NewUnlock event") 587 } 588 589 func ensureProposal(proposalCh <-chan tmpubsub.Message, height int64, round int32, propID types.BlockID) { 590 select { 591 case <-time.After(ensureTimeout): 592 panic("Timeout expired while waiting for NewProposal event") 593 case msg := <-proposalCh: 594 proposalEvent, ok := msg.Data().(types.EventDataCompleteProposal) 595 if !ok { 596 panic(fmt.Sprintf("expected a EventDataCompleteProposal, got %T. Wrong subscription channel?", 597 msg.Data())) 598 } 599 if proposalEvent.Height != height { 600 panic(fmt.Sprintf("expected height %v, got %v", height, proposalEvent.Height)) 601 } 602 if proposalEvent.Round != round { 603 panic(fmt.Sprintf("expected round %v, got %v", round, proposalEvent.Round)) 604 } 605 if !proposalEvent.BlockID.Equals(propID) { 606 panic(fmt.Sprintf("Proposed block does not match expected block (%v != %v)", proposalEvent.BlockID, propID)) 607 } 608 } 609 } 610 611 func ensurePrecommit(voteCh <-chan tmpubsub.Message, height int64, round int32) { 612 ensureVote(voteCh, height, round, tmproto.PrecommitType) 613 } 614 615 func ensurePrevote(voteCh <-chan tmpubsub.Message, height int64, round int32) { 616 ensureVote(voteCh, height, round, tmproto.PrevoteType) 617 } 618 619 func ensureVote(voteCh <-chan tmpubsub.Message, height int64, round int32, 620 voteType tmproto.SignedMsgType) { 621 select { 622 case <-time.After(ensureTimeout): 623 panic("Timeout expired while waiting for NewVote event") 624 case msg := <-voteCh: 625 voteEvent, ok := msg.Data().(types.EventDataVote) 626 if !ok { 627 panic(fmt.Sprintf("expected a EventDataVote, got %T. Wrong subscription channel?", 628 msg.Data())) 629 } 630 vote := voteEvent.Vote 631 if vote.Height != height { 632 panic(fmt.Sprintf("expected height %v, got %v", height, vote.Height)) 633 } 634 if vote.Round != round { 635 panic(fmt.Sprintf("expected round %v, got %v", round, vote.Round)) 636 } 637 if vote.Type != voteType { 638 panic(fmt.Sprintf("expected type %v, got %v", voteType, vote.Type)) 639 } 640 } 641 } 642 643 func ensurePrecommitTimeout(ch <-chan tmpubsub.Message) { 644 select { 645 case <-time.After(ensureTimeout): 646 panic("Timeout expired while waiting for the Precommit to Timeout") 647 case <-ch: 648 } 649 } 650 651 func ensureNewEventOnChannel(ch <-chan tmpubsub.Message) { 652 select { 653 case <-time.After(ensureTimeout): 654 panic("Timeout expired while waiting for new activity on the channel") 655 case <-ch: 656 } 657 } 658 659 //------------------------------------------------------------------------------- 660 // consensus nets 661 662 // consensusLogger is a TestingLogger which uses a different 663 // color for each validator ("validator" key must exist). 664 func consensusLogger() log.Logger { 665 return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor { 666 for i := 0; i < len(keyvals)-1; i += 2 { 667 if keyvals[i] == "validator" { 668 return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))} 669 } 670 } 671 return term.FgBgColor{} 672 }).With("module", "consensus") 673 } 674 675 func randConsensusNet(nValidators int, testName string, tickerFunc func() TimeoutTicker, 676 appFunc func() abci.Application, configOpts ...func(*cfg.Config)) ([]*State, cleanupFunc) { 677 genDoc, privVals := randGenesisDoc(nValidators, false, 30) 678 css := make([]*State, nValidators) 679 logger := consensusLogger() 680 configRootDirs := make([]string, 0, nValidators) 681 for i := 0; i < nValidators; i++ { 682 stateDB := dbm.NewMemDB() // each state needs its own db 683 stateStore := sm.NewStore(stateDB) 684 state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc) 685 thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i)) 686 configRootDirs = append(configRootDirs, thisConfig.RootDir) 687 for _, opt := range configOpts { 688 opt(thisConfig) 689 } 690 ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal 691 app := appFunc() 692 vals := types.TM2PB.ValidatorUpdates(state.Validators) 693 app.InitChain(abci.RequestInitChain{Validators: vals}) 694 695 css[i] = newStateWithConfigAndBlockStore(thisConfig, state, privVals[i], app, stateDB) 696 css[i].SetTimeoutTicker(tickerFunc()) 697 css[i].SetLogger(logger.With("validator", i, "module", "consensus")) 698 } 699 return css, func() { 700 for _, dir := range configRootDirs { 701 os.RemoveAll(dir) 702 } 703 } 704 } 705 706 // nPeers = nValidators + nNotValidator 707 func randConsensusNetWithPeers( 708 nValidators, 709 nPeers int, 710 testName string, 711 tickerFunc func() TimeoutTicker, 712 appFunc func(string) abci.Application, 713 ) ([]*State, *types.GenesisDoc, *cfg.Config, cleanupFunc) { 714 genDoc, privVals := randGenesisDoc(nValidators, false, testMinPower) 715 css := make([]*State, nPeers) 716 logger := consensusLogger() 717 var peer0Config *cfg.Config 718 configRootDirs := make([]string, 0, nPeers) 719 for i := 0; i < nPeers; i++ { 720 stateDB := dbm.NewMemDB() // each state needs its own db 721 stateStore := sm.NewStore(stateDB) 722 state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc) 723 thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i)) 724 configRootDirs = append(configRootDirs, thisConfig.RootDir) 725 ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal 726 if i == 0 { 727 peer0Config = thisConfig 728 } 729 var privVal types.PrivValidator 730 if i < nValidators { 731 privVal = privVals[i] 732 } else { 733 tempKeyFile, err := ioutil.TempFile("", "priv_validator_key_") 734 if err != nil { 735 panic(err) 736 } 737 tempStateFile, err := ioutil.TempFile("", "priv_validator_state_") 738 if err != nil { 739 panic(err) 740 } 741 742 privVal = privval.GenFilePV(tempKeyFile.Name(), tempStateFile.Name()) 743 } 744 745 app := appFunc(path.Join(config.DBDir(), fmt.Sprintf("%s_%d", testName, i))) 746 vals := types.TM2PB.ValidatorUpdates(state.Validators) 747 if _, ok := app.(*kvstore.PersistentKVStoreApplication); ok { 748 // simulate handshake, receive app version. If don't do this, replay test will fail 749 state.Version.Consensus.App = kvstore.ProtocolVersion 750 } 751 app.InitChain(abci.RequestInitChain{Validators: vals}) 752 // sm.SaveState(stateDB,state) //height 1's validatorsInfo already saved in LoadStateFromDBOrGenesisDoc above 753 754 css[i] = newStateWithConfig(thisConfig, state, privVal, app) 755 css[i].SetTimeoutTicker(tickerFunc()) 756 css[i].SetLogger(logger.With("validator", i, "module", "consensus")) 757 } 758 return css, genDoc, peer0Config, func() { 759 for _, dir := range configRootDirs { 760 os.RemoveAll(dir) 761 } 762 } 763 } 764 765 func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int { 766 for i, s := range switches { 767 if peer.NodeInfo().ID() == s.NodeInfo().ID() { 768 return i 769 } 770 } 771 panic("didnt find peer in switches") 772 } 773 774 //------------------------------------------------------------------------------- 775 // genesis 776 777 func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) { 778 validators := make([]types.GenesisValidator, numValidators) 779 privValidators := make([]types.PrivValidator, numValidators) 780 for i := 0; i < numValidators; i++ { 781 val, privVal := types.RandValidator(randPower, minPower) 782 validators[i] = types.GenesisValidator{ 783 PubKey: val.PubKey, 784 Power: val.VotingPower, 785 } 786 privValidators[i] = privVal 787 } 788 sort.Sort(types.PrivValidatorsByAddress(privValidators)) 789 790 return &types.GenesisDoc{ 791 GenesisTime: tmtime.Now(), 792 InitialHeight: 1, 793 ChainID: config.ChainID(), 794 Validators: validators, 795 }, privValidators 796 } 797 798 func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []types.PrivValidator) { 799 genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower) 800 s0, _ := sm.MakeGenesisState(genDoc) 801 return s0, privValidators 802 } 803 804 //------------------------------------ 805 // mock ticker 806 807 func newMockTickerFunc(onlyOnce bool) func() TimeoutTicker { 808 return func() TimeoutTicker { 809 return &mockTicker{ 810 c: make(chan timeoutInfo, 10), 811 onlyOnce: onlyOnce, 812 } 813 } 814 } 815 816 // mock ticker only fires on RoundStepNewHeight 817 // and only once if onlyOnce=true 818 type mockTicker struct { 819 c chan timeoutInfo 820 821 mtx sync.Mutex 822 onlyOnce bool 823 fired bool 824 } 825 826 func (m *mockTicker) Start() error { 827 return nil 828 } 829 830 func (m *mockTicker) Stop() error { 831 return nil 832 } 833 834 func (m *mockTicker) ScheduleTimeout(ti timeoutInfo) { 835 m.mtx.Lock() 836 defer m.mtx.Unlock() 837 if m.onlyOnce && m.fired { 838 return 839 } 840 if ti.Step == cstypes.RoundStepNewHeight { 841 m.c <- ti 842 m.fired = true 843 } 844 } 845 846 func (m *mockTicker) Chan() <-chan timeoutInfo { 847 return m.c 848 } 849 850 func (*mockTicker) SetLogger(log.Logger) {} 851 852 //------------------------------------ 853 854 func newCounter() abci.Application { 855 return counter.NewApplication(true) 856 } 857 858 func newPersistentKVStore() abci.Application { 859 dir, err := ioutil.TempDir("", "persistent-kvstore") 860 if err != nil { 861 panic(err) 862 } 863 return kvstore.NewPersistentKVStoreApplication(dir) 864 } 865 866 func newPersistentKVStoreWithPath(dbDir string) abci.Application { 867 return kvstore.NewPersistentKVStoreApplication(dbDir) 868 }