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