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  }