github.com/Finschia/ostracon@v1.1.5/consensus/state_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/mock"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	abci "github.com/tendermint/tendermint/abci/types"
    15  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    16  
    17  	"github.com/Finschia/ostracon/abci/example/counter"
    18  	ocabci "github.com/Finschia/ostracon/abci/types"
    19  	"github.com/Finschia/ostracon/abci/types/mocks"
    20  	cstypes "github.com/Finschia/ostracon/consensus/types"
    21  	"github.com/Finschia/ostracon/crypto/tmhash"
    22  	"github.com/Finschia/ostracon/libs/log"
    23  	tmpubsub "github.com/Finschia/ostracon/libs/pubsub"
    24  	tmrand "github.com/Finschia/ostracon/libs/rand"
    25  	p2pmock "github.com/Finschia/ostracon/p2p/mock"
    26  	"github.com/Finschia/ostracon/types"
    27  )
    28  
    29  /*
    30  
    31  ProposeSuite
    32  x * TestProposerSelection0 - round robin ordering, round 0
    33  x * TestProposerSelection2 - round robin ordering, round 2++
    34  x * TestEnterProposeNoValidator - timeout into prevote round
    35  x * TestEnterPropose - finish propose without timing out (we have the proposal)
    36  x * TestBadProposal - 2 vals, bad proposal (bad block state hash), should prevote and precommit nil
    37  x * TestOversizedBlock - block with too many txs should be rejected
    38  FullRoundSuite
    39  x * TestFullRound1 - 1 val, full successful round
    40  x * TestFullRoundNil - 1 val, full round of nil
    41  x * TestFullRound2 - 2 vals, both required for full round
    42  LockSuite
    43  x * TestLockNoPOL - 2 vals, 4 rounds. one val locked, precommits nil every round except first.
    44  x * TestLockPOLRelock - 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
    45  x * TestLockPOLUnlock - 4 vals, one precommits, other 3 polka nil at next round, so we unlock and precomit nil
    46  x * TestLockPOLSafety1 - 4 vals. We shouldn't change lock based on polka at earlier round
    47  x * TestLockPOLSafety2 - 4 vals. After unlocking, we shouldn't relock based on polka at earlier round
    48    * TestNetworkLock - once +1/3 precommits, network should be locked
    49    * TestNetworkLockPOL - once +1/3 precommits, the block with more recent polka is committed
    50  SlashingSuite
    51  x * TestSlashingPrevotes - a validator prevoting twice in a round gets slashed
    52  x * TestSlashingPrecommits - a validator precomitting twice in a round gets slashed
    53  CatchupSuite
    54    * TestCatchup - if we might be behind and we've seen any 2/3 prevotes, round skip to new round, precommit, or prevote
    55  HaltSuite
    56  x * TestHalt1 - if we see +2/3 precommits after timing out into new round, we should still commit
    57  
    58  */
    59  
    60  //----------------------------------------------------------------------------------------------------
    61  // ProposeSuite
    62  
    63  func TestStateProposerSelection0(t *testing.T) {
    64  	cs1, vss := randState(4)
    65  	height, round := cs1.Height, cs1.Round
    66  
    67  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
    68  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
    69  
    70  	startTestRound(cs1, height, round)
    71  
    72  	// Wait for new round so proposer is set.
    73  	ensureNewRound(newRoundCh, height, round)
    74  
    75  	// Commit a block and ensure proposer for the next height is correct.
    76  	prop := cs1.GetRoundState().Proposer
    77  	pv, err := cs1.privValidator.GetPubKey()
    78  	require.NoError(t, err)
    79  	address := pv.Address()
    80  	if !bytes.Equal(prop.Address, address) {
    81  		t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
    82  	}
    83  
    84  	// Wait for complete proposal.
    85  	ensureNewProposal(proposalCh, height, round)
    86  
    87  	rs := cs1.GetRoundState()
    88  	signAddVotes(cs1, tmproto.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
    89  
    90  	// Wait for new round so next validator is set.
    91  	ensureNewRound(newRoundCh, height+1, 0)
    92  
    93  	prop = cs1.GetRoundState().Proposer
    94  	addr := cs1.Validators.SelectProposer(cs1.state.LastProofHash, cs1.Height, cs1.Round).PubKey.Address()
    95  	if !bytes.Equal(prop.Address, addr) {
    96  		panic(fmt.Sprintf("expected proposer to be validator %d. Got %X", 1, prop.Address))
    97  	}
    98  }
    99  
   100  // Now let's do it all again, but starting from round 2 instead of 0
   101  func TestStateProposerSelection2(t *testing.T) {
   102  	cs1, vss := randState(4) // test needs more work for more than 3 validators
   103  	height := cs1.Height
   104  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   105  
   106  	// this time we jump in at round 2
   107  	incrementRound(vss[1:]...)
   108  	incrementRound(vss[1:]...)
   109  
   110  	var round int32 = 2
   111  	startTestRound(cs1, height, round)
   112  
   113  	ensureNewRound(newRoundCh, height, round) // wait for the new round
   114  
   115  	// everyone just votes nil. we get a new proposer each round
   116  	for i := int32(0); int(i) < len(vss); i++ {
   117  		prop := cs1.GetRoundState().Proposer
   118  		addr := cs1.Validators.SelectProposer(cs1.state.LastProofHash, height, i+round).PubKey.Address()
   119  		correctProposer := addr
   120  		if !bytes.Equal(prop.Address, correctProposer) {
   121  			idx, _ := cs1.Validators.GetByAddress(addr)
   122  			panic(fmt.Sprintf(
   123  				"expected RoundState.Validators.GetProposer() to be validator %d. Got %X",
   124  				idx,
   125  				prop.Address))
   126  		}
   127  
   128  		rs := cs1.GetRoundState()
   129  		signAddVotes(cs1, tmproto.PrecommitType, nil, rs.ProposalBlockParts.Header(), vss[1:]...)
   130  		ensureNewRound(newRoundCh, height, i+round+1) // wait for the new round event each round
   131  		incrementRound(vss[1:]...)
   132  	}
   133  
   134  }
   135  
   136  // a non-validator should timeout into the prevote round
   137  func TestStateEnterProposeNoPrivValidator(t *testing.T) {
   138  	cs, _ := randState(1)
   139  	cs.SetPrivValidator(nil)
   140  	height, round := cs.Height, cs.Round
   141  
   142  	// Listen for propose timeout event
   143  	timeoutCh := subscribe(cs.eventBus, types.EventQueryTimeoutPropose)
   144  
   145  	startTestRound(cs, height, round)
   146  
   147  	// if we're not a validator, EnterPropose should timeout
   148  	ensureNewTimeout(timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
   149  
   150  	if cs.GetRoundState().Proposal != nil {
   151  		t.Error("Expected to make no proposal, since no privValidator")
   152  	}
   153  }
   154  
   155  // a validator should not timeout of the prevote round (TODO: unless the block is really big!)
   156  func TestStateEnterProposeYesPrivValidator(t *testing.T) {
   157  	cs, _ := randState(1)
   158  	height, round := cs.Height, cs.Round
   159  
   160  	// Listen for propose timeout event
   161  
   162  	timeoutCh := subscribe(cs.eventBus, types.EventQueryTimeoutPropose)
   163  	proposalCh := subscribe(cs.eventBus, types.EventQueryCompleteProposal)
   164  
   165  	cs.enterNewRound(height, round)
   166  	cs.startRoutines(3)
   167  
   168  	ensureNewProposal(proposalCh, height, round)
   169  
   170  	// Check that Proposal, ProposalBlock, ProposalBlockParts are set.
   171  	rs := cs.GetRoundState()
   172  	if rs.Proposal == nil {
   173  		t.Error("rs.Proposal should be set")
   174  	}
   175  	if rs.ProposalBlock == nil {
   176  		t.Error("rs.ProposalBlock should be set")
   177  	}
   178  	if rs.ProposalBlockParts.Total() == 0 {
   179  		t.Error("rs.ProposalBlockParts should be set")
   180  	}
   181  
   182  	// if we're a validator, enterPropose should not timeout
   183  	ensureNoNewTimeout(timeoutCh, cs.config.TimeoutPropose.Nanoseconds())
   184  }
   185  
   186  func TestStateBadProposal(t *testing.T) {
   187  	cs1, vss := randState(2)
   188  	height, round := cs1.Height, cs1.Round
   189  	vs2 := vss[1]
   190  
   191  	partSize := types.BlockPartSizeBytes
   192  
   193  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   194  	voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
   195  
   196  	propBlock, _ := cs1.createProposalBlock(round) // changeProposer(t, cs1, vs2)
   197  
   198  	// make the second validator the proposer by incrementing round
   199  	round++
   200  	incrementRound(vss[1:]...)
   201  
   202  	// make the block bad by tampering with statehash
   203  	stateHash := propBlock.AppHash
   204  	if len(stateHash) == 0 {
   205  		stateHash = make([]byte, 32)
   206  	}
   207  	stateHash[0] = (stateHash[0] + 1) % 255
   208  	propBlock.AppHash = stateHash
   209  	propBlockParts := propBlock.MakePartSet(partSize)
   210  	blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
   211  	proposal := types.NewProposal(vs2.Height, round, -1, blockID)
   212  	p := proposal.ToProto()
   213  	if err := vs2.SignProposal(config.ChainID(), p); err != nil {
   214  		t.Fatal("failed to sign bad proposal", err)
   215  	}
   216  
   217  	proposal.Signature = p.Signature
   218  
   219  	// set the proposal block
   220  	if err := cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   221  		t.Fatal(err)
   222  	}
   223  
   224  	// start the machine
   225  	startTestRound(cs1, height, round)
   226  
   227  	// wait for proposal
   228  	ensureProposal(proposalCh, height, round, blockID)
   229  
   230  	// wait for prevote
   231  	ensurePrevote(voteCh, height, round)
   232  	validatePrevote(t, cs1, round, vss[0], nil)
   233  
   234  	// add bad prevote from vs2 and wait for it
   235  	signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
   236  	ensurePrevote(voteCh, height, round)
   237  
   238  	// wait for precommit
   239  	ensurePrecommit(voteCh, height, round)
   240  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
   241  	signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
   242  }
   243  
   244  func TestStateOversizedBlock(t *testing.T) {
   245  	cs1, vss := randState(2)
   246  	cs1.state.ConsensusParams.Block.MaxBytes = 2000
   247  	height, round := cs1.Height, cs1.Round
   248  	vs2 := vss[1]
   249  
   250  	forceProposer(cs1, vss, []int{1, 1}, []int64{height, height}, []int32{round, round + 1})
   251  
   252  	partSize := types.BlockPartSizeBytes
   253  
   254  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
   255  	voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
   256  
   257  	propBlock, _ := cs1.createProposalBlock(round)
   258  	propBlock.Data.Txs = []types.Tx{tmrand.Bytes(2001)}
   259  	propBlock.Header.DataHash = propBlock.Data.Hash()
   260  
   261  	// make the second validator the proposer by incrementing round
   262  	round++
   263  	incrementRound(vss[1:]...)
   264  
   265  	propBlockParts := propBlock.MakePartSet(partSize)
   266  	blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
   267  	proposal := types.NewProposal(height, round, -1, blockID)
   268  	p := proposal.ToProto()
   269  	if err := vs2.SignProposal(config.ChainID(), p); err != nil {
   270  		t.Fatal("failed to sign bad proposal", err)
   271  	}
   272  	proposal.Signature = p.Signature
   273  
   274  	totalBytes := 0
   275  	for i := 0; i < int(propBlockParts.Total()); i++ {
   276  		part := propBlockParts.GetPart(i)
   277  		totalBytes += len(part.Bytes)
   278  	}
   279  
   280  	if err := cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
   281  		t.Fatal(err)
   282  	}
   283  
   284  	// start the machine
   285  	startTestRound(cs1, height, round)
   286  
   287  	t.Log("Block Sizes", "Limit", cs1.state.ConsensusParams.Block.MaxBytes, "Current", totalBytes)
   288  
   289  	// c1 should log an error with the block part message as it exceeds the consensus params. The
   290  	// block is not added to cs.ProposalBlock so the node timeouts.
   291  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
   292  
   293  	// and then should send nil prevote and precommit regardless of whether other validators prevote and
   294  	// precommit on it
   295  	ensurePrevote(voteCh, height, round)
   296  	validatePrevote(t, cs1, round, vss[0], nil)
   297  	signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
   298  	ensurePrevote(voteCh, height, round)
   299  	ensurePrecommit(voteCh, height, round)
   300  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
   301  	signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
   302  }
   303  
   304  //----------------------------------------------------------------------------------------------------
   305  // FullRoundSuite
   306  
   307  // propose, prevote, and precommit a block
   308  func TestStateFullRound1(t *testing.T) {
   309  	cs, vss := randState(1)
   310  	height, round := cs.Height, cs.Round
   311  
   312  	// NOTE: buffer capacity of 0 ensures we can validate prevote and last commit
   313  	// before consensus can move to the next height (and cause a race condition)
   314  	if err := cs.eventBus.Stop(); err != nil {
   315  		t.Error(err)
   316  	}
   317  	eventBus := types.NewEventBusWithBufferCapacity(0)
   318  	eventBus.SetLogger(log.TestingLogger().With("module", "events"))
   319  	cs.SetEventBus(eventBus)
   320  	if err := eventBus.Start(); err != nil {
   321  		t.Error(err)
   322  	}
   323  
   324  	voteCh := subscribeUnBuffered(cs.eventBus, types.EventQueryVote)
   325  	propCh := subscribe(cs.eventBus, types.EventQueryCompleteProposal)
   326  	newRoundCh := subscribe(cs.eventBus, types.EventQueryNewRound)
   327  
   328  	// Maybe it would be better to call explicitly startRoutines(4)
   329  	startTestRound(cs, height, round)
   330  
   331  	ensureNewRound(newRoundCh, height, round)
   332  
   333  	ensureNewProposal(propCh, height, round)
   334  	propBlockHash := cs.GetRoundState().ProposalBlock.Hash()
   335  
   336  	ensurePrevote(voteCh, height, round) // wait for prevote
   337  	validatePrevote(t, cs, round, vss[0], propBlockHash)
   338  
   339  	ensurePrecommit(voteCh, height, round) // wait for precommit
   340  
   341  	// we're going to roll right into new height
   342  	ensureNewRound(newRoundCh, height+1, 0)
   343  
   344  	validateLastPrecommit(t, cs, vss[0], propBlockHash)
   345  }
   346  
   347  // nil is proposed, so prevote and precommit nil
   348  func TestStateFullRoundNil(t *testing.T) {
   349  	cs, vss := randState(1)
   350  	height, round := cs.Height, cs.Round
   351  
   352  	voteCh := subscribeUnBuffered(cs.eventBus, types.EventQueryVote)
   353  
   354  	cs.enterPrevote(height, round)
   355  	cs.startRoutines(4)
   356  
   357  	ensurePrevote(voteCh, height, round)   // prevote
   358  	ensurePrecommit(voteCh, height, round) // precommit
   359  
   360  	// should prevote and precommit nil
   361  	validatePrevoteAndPrecommit(t, cs, round, -1, vss[0], nil, nil)
   362  }
   363  
   364  // run through propose, prevote, precommit commit with two validators
   365  // where the first validator has to wait for votes from the second
   366  func TestStateFullRound2(t *testing.T) {
   367  	cs1, vss := randState(2)
   368  	vs2 := vss[1]
   369  	height, round := cs1.Height, cs1.Round
   370  
   371  	voteCh := subscribeUnBuffered(cs1.eventBus, types.EventQueryVote)
   372  	newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
   373  
   374  	// start round and wait for propose and prevote
   375  	startTestRound(cs1, height, round)
   376  
   377  	ensurePrevote(voteCh, height, round) // prevote
   378  
   379  	// we should be stuck in limbo waiting for more prevotes
   380  	rs := cs1.GetRoundState()
   381  	propBlockHash, propPartSetHeader := rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header()
   382  
   383  	// prevote arrives from vs2:
   384  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propPartSetHeader, vs2)
   385  	ensurePrevote(voteCh, height, round) // prevote
   386  
   387  	ensurePrecommit(voteCh, height, round) // precommit
   388  	// the proposed block should now be locked and our precommit added
   389  	validatePrecommit(t, cs1, 0, 0, vss[0], propBlockHash, propBlockHash)
   390  
   391  	// we should be stuck in limbo waiting for more precommits
   392  
   393  	// precommit arrives from vs2:
   394  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash, propPartSetHeader, vs2)
   395  	ensurePrecommit(voteCh, height, round)
   396  
   397  	// wait to finish commit, propose in next height
   398  	ensureNewBlock(newBlockCh, height)
   399  }
   400  
   401  //------------------------------------------------------------------------------------------
   402  // LockSuite
   403  
   404  // two validators, 4 rounds.
   405  // two vals take turns proposing. val1 locks on first one, precommits nil on everything else
   406  func TestStateLockNoPOL(t *testing.T) {
   407  	cs1, vss := randState(2)
   408  	// set the lastProofHash that the proposer order is 0,1,0,1
   409  	forceProposer(cs1, vss, []int{0, 1, 0, 1}, []int64{1, 1, 1, 1}, []int32{0, 1, 2, 3})
   410  
   411  	vs2 := vss[1]
   412  	height, round := cs1.Height, cs1.Round
   413  
   414  	partSize := types.BlockPartSizeBytes
   415  
   416  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
   417  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
   418  	voteCh := subscribeUnBuffered(cs1.eventBus, types.EventQueryVote)
   419  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   420  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   421  
   422  	/*
   423  		Round1 (cs1, B) // B B // B B2
   424  	*/
   425  
   426  	// start round and wait for prevote
   427  	cs1.enterNewRound(height, round)
   428  	cs1.startRoutines(0)
   429  
   430  	ensureNewRound(newRoundCh, height, round)
   431  
   432  	ensureNewProposal(proposalCh, height, round)
   433  	roundState := cs1.GetRoundState()
   434  	theBlockHash := roundState.ProposalBlock.Hash()
   435  	thePartSetHeader := roundState.ProposalBlockParts.Header()
   436  
   437  	ensurePrevote(voteCh, height, round) // prevote
   438  
   439  	// we should now be stuck in limbo forever, waiting for more prevotes
   440  	// prevote arrives from vs2:
   441  	signAddVotes(cs1, tmproto.PrevoteType, theBlockHash, thePartSetHeader, vs2)
   442  	ensurePrevote(voteCh, height, round) // prevote
   443  
   444  	ensurePrecommit(voteCh, height, round) // precommit
   445  	// the proposed block should now be locked and our precommit added
   446  	validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
   447  
   448  	// we should now be stuck in limbo forever, waiting for more precommits
   449  	// lets add one for a different block
   450  	hash := make([]byte, len(theBlockHash))
   451  	copy(hash, theBlockHash)
   452  	hash[0] = (hash[0] + 1) % 255
   453  	signAddVotes(cs1, tmproto.PrecommitType, hash, thePartSetHeader, vs2)
   454  	ensurePrecommit(voteCh, height, round) // precommit
   455  
   456  	// (note we're entering precommit for a second time this round)
   457  	// but with invalid args. then we enterPrecommitWait, and the timeout to new round
   458  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   459  
   460  	///
   461  
   462  	round++ // moving to the next round
   463  	ensureNewRound(newRoundCh, height, round)
   464  	t.Log("#### ONTO ROUND 1")
   465  	/*
   466  		Round2 (cs1, B) // B B2
   467  	*/
   468  
   469  	incrementRound(vs2)
   470  
   471  	// now we're on a new round and not the proposer, so wait for timeout
   472  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
   473  
   474  	rs := cs1.GetRoundState()
   475  
   476  	if rs.ProposalBlock != nil {
   477  		panic("Expected proposal block to be nil")
   478  	}
   479  
   480  	// wait to finish prevote
   481  	ensurePrevote(voteCh, height, round)
   482  	// we should have prevoted our locked block
   483  	validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash())
   484  
   485  	// add a conflicting prevote from the other validator
   486  	signAddVotes(cs1, tmproto.PrevoteType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
   487  	ensurePrevote(voteCh, height, round)
   488  
   489  	// now we're going to enter prevote again, but with invalid args
   490  	// and then prevote wait, which should timeout. then wait for precommit
   491  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
   492  
   493  	ensurePrecommit(voteCh, height, round) // precommit
   494  	// the proposed block should still be locked and our precommit added
   495  	// we should precommit nil and be locked on the proposal
   496  	validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash)
   497  
   498  	// add conflicting precommit from vs2
   499  	signAddVotes(cs1, tmproto.PrecommitType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
   500  	ensurePrecommit(voteCh, height, round)
   501  
   502  	// (note we're entering precommit for a second time this round, but with invalid args
   503  	// then we enterPrecommitWait and timeout into NewRound
   504  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   505  
   506  	round++ // entering new round
   507  	ensureNewRound(newRoundCh, height, round)
   508  	t.Log("#### ONTO ROUND 2")
   509  	/*
   510  		Round3 (vs2, _) // B, B2
   511  	*/
   512  
   513  	incrementRound(vs2)
   514  
   515  	ensureNewProposal(proposalCh, height, round)
   516  	rs = cs1.GetRoundState()
   517  
   518  	// now we're on a new round and are the proposer
   519  	if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
   520  		panic(fmt.Sprintf(
   521  			"Expected proposal block to be locked block. Got %v, Expected %v",
   522  			rs.ProposalBlock,
   523  			rs.LockedBlock))
   524  	}
   525  
   526  	ensurePrevote(voteCh, height, round) // prevote
   527  	validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash())
   528  
   529  	signAddVotes(cs1, tmproto.PrevoteType, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
   530  	ensurePrevote(voteCh, height, round)
   531  
   532  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
   533  	ensurePrecommit(voteCh, height, round) // precommit
   534  
   535  	validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal
   536  
   537  	signAddVotes(
   538  		cs1,
   539  		tmproto.PrecommitType,
   540  		hash,
   541  		rs.ProposalBlock.MakePartSet(partSize).Header(),
   542  		vs2) // NOTE: conflicting precommits at same height
   543  	ensurePrecommit(voteCh, height, round)
   544  
   545  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   546  
   547  	cs2, _ := randState(2) // needed so generated block is different than locked block
   548  	// before we time out into new round, set next proposal block
   549  	prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1)
   550  	if prop == nil || propBlock == nil {
   551  		t.Fatal("Failed to create proposal block with vs2")
   552  	}
   553  
   554  	incrementRound(vs2)
   555  
   556  	round++ // entering new round
   557  	ensureNewRound(newRoundCh, height, round)
   558  	t.Log("#### ONTO ROUND 3")
   559  	/*
   560  		Round4 (vs2, C) // B C // B C
   561  	*/
   562  
   563  	// now we're on a new round and not the proposer
   564  	// so set the proposal block
   565  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(partSize), ""); err != nil {
   566  		t.Fatal(err)
   567  	}
   568  
   569  	ensureNewProposal(proposalCh, height, round)
   570  	ensurePrevote(voteCh, height, round) // prevote
   571  	// prevote for locked block (not proposal)
   572  	validatePrevote(t, cs1, 3, vss[0], cs1.LockedBlock.Hash())
   573  
   574  	// prevote for proposed block
   575  	signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
   576  	ensurePrevote(voteCh, height, round)
   577  
   578  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
   579  	ensurePrecommit(voteCh, height, round)
   580  	validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal
   581  
   582  	signAddVotes(
   583  		cs1,
   584  		tmproto.PrecommitType,
   585  		propBlock.Hash(),
   586  		propBlock.MakePartSet(partSize).Header(),
   587  		vs2) // NOTE: conflicting precommits at same height
   588  	ensurePrecommit(voteCh, height, round)
   589  }
   590  
   591  // 4 vals in two rounds,
   592  // in round one: v1 precommits, other 3 only prevote so the block isn't committed
   593  // in round two: v1 prevotes the same block that the node is locked on
   594  // the others prevote a new block hence v1 changes lock and precommits the new block with the others
   595  func TestStateLockPOLRelock(t *testing.T) {
   596  	cs1, vss := randState(4)
   597  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
   598  	height, round := cs1.Height, cs1.Round
   599  
   600  	partSize := types.BlockPartSizeBytes
   601  
   602  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
   603  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   604  	pv1, err := cs1.privValidator.GetPubKey()
   605  	require.NoError(t, err)
   606  	addr := pv1.Address()
   607  	voteCh := subscribeToVoter(cs1, addr)
   608  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   609  	newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
   610  
   611  	// everything done from perspective of cs1
   612  
   613  	/*
   614  		Round1 (cs1, B) // B B B B// B nil B nil
   615  
   616  		eg. vs2 and vs4 didn't see the 2/3 prevotes
   617  	*/
   618  
   619  	// force the vss[0], vss[1] to become a proposer by turns
   620  	forceProposer(cs1, vss, []int{0, 1, 0}, []int64{height, height, height + 1}, []int32{round, round + 1, 0})
   621  
   622  	// start round and wait for propose and prevote
   623  	startTestRound(cs1, height, round)
   624  
   625  	ensureNewRound(newRoundCh, height, round)
   626  	ensureNewProposal(proposalCh, height, round)
   627  	rs := cs1.GetRoundState()
   628  	theBlockHash := rs.ProposalBlock.Hash()
   629  	theBlockParts := rs.ProposalBlockParts.Header()
   630  
   631  	ensurePrevote(voteCh, height, round) // prevote
   632  
   633  	signAddVotes(cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
   634  
   635  	ensurePrecommit(voteCh, height, round) // our precommit
   636  	// the proposed block should now be locked and our precommit added
   637  	validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
   638  
   639  	// add precommits from the rest
   640  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
   641  
   642  	// before we timeout to the new round set the new proposal
   643  	cs2 := newState(cs1.state, vs2, counter.NewApplication(true))
   644  	prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1)
   645  	if prop == nil || propBlock == nil {
   646  		t.Fatal("Failed to create proposal block with vs2")
   647  	}
   648  
   649  	propBlockParts := propBlock.MakePartSet(partSize)
   650  	propBlockHash := propBlock.Hash()
   651  	require.NotEqual(t, propBlockHash, theBlockHash)
   652  
   653  	incrementRound(vs2, vs3, vs4)
   654  
   655  	// timeout to new round
   656  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   657  
   658  	round++ // moving to the next round
   659  	//XXX: this isnt guaranteed to get there before the timeoutPropose ...
   660  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
   661  		t.Fatal(err)
   662  	}
   663  
   664  	ensureNewRound(newRoundCh, height, round)
   665  	t.Log("### ONTO ROUND 1")
   666  
   667  	/*
   668  		Round2 (vs2, C) // B C C C // C C C _)
   669  
   670  		cs1 changes lock!
   671  	*/
   672  
   673  	// now we're on a new round and not the proposer
   674  	// but we should receive the proposal
   675  	ensureNewProposal(proposalCh, height, round)
   676  
   677  	// go to prevote, node should prevote for locked block (not the new proposal) - this is relocking
   678  	ensurePrevote(voteCh, height, round)
   679  	validatePrevote(t, cs1, round, vss[0], theBlockHash)
   680  
   681  	// now lets add prevotes from everyone else for the new block
   682  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
   683  
   684  	ensurePrecommit(voteCh, height, round)
   685  	// we should have unlocked and locked on the new block, sending a precommit for this new block
   686  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
   687  
   688  	// more prevote creating a majority on the new block and this is then committed
   689  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3)
   690  	ensureNewBlockHeader(newBlockCh, height, propBlockHash)
   691  
   692  	ensureNewRound(newRoundCh, height+1, 0)
   693  }
   694  
   695  // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
   696  func TestStateLockPOLUnlock(t *testing.T) {
   697  	cs1, vss := randState(4)
   698  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
   699  	height, round := cs1.Height, cs1.Round
   700  
   701  	partSize := types.BlockPartSizeBytes
   702  
   703  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   704  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
   705  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   706  	unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
   707  	pv1, err := cs1.privValidator.GetPubKey()
   708  	require.NoError(t, err)
   709  	addr := pv1.Address()
   710  	voteCh := subscribeToVoter(cs1, addr)
   711  
   712  	// everything done from perspective of cs1
   713  
   714  	/*
   715  		Round1 (cs1, B) // B B B B // B nil B nil
   716  		eg. didn't see the 2/3 prevotes
   717  	*/
   718  
   719  	// force the vss[0], vss[1] to become a proposer by turns
   720  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height}, []int32{round, round + 1})
   721  
   722  	// start round and wait for propose and prevote
   723  	startTestRound(cs1, height, round)
   724  	ensureNewRound(newRoundCh, height, round)
   725  
   726  	ensureNewProposal(proposalCh, height, round)
   727  	rs := cs1.GetRoundState()
   728  	theBlockHash := rs.ProposalBlock.Hash()
   729  	theBlockParts := rs.ProposalBlockParts.Header()
   730  
   731  	ensurePrevote(voteCh, height, round)
   732  	validatePrevote(t, cs1, round, vss[0], theBlockHash)
   733  
   734  	signAddVotes(cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
   735  
   736  	ensurePrecommit(voteCh, height, round)
   737  	// the proposed block should now be locked and our precommit added
   738  	validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
   739  
   740  	// add precommits from the rest
   741  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs4)
   742  	signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3)
   743  
   744  	// before we time out into new round, set next proposal block
   745  	prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
   746  	propBlockParts := propBlock.MakePartSet(partSize)
   747  
   748  	// timeout to new round
   749  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   750  	rs = cs1.GetRoundState()
   751  	lockedBlockHash := rs.LockedBlock.Hash()
   752  
   753  	incrementRound(vs2, vs3, vs4)
   754  	round++ // moving to the next round
   755  
   756  	ensureNewRound(newRoundCh, height, round)
   757  	t.Log("#### ONTO ROUND 1")
   758  	/*
   759  		Round2 (vs2, C) // B nil nil nil // nil nil nil _
   760  		cs1 unlocks!
   761  	*/
   762  	//XXX: this isnt guaranteed to get there before the timeoutPropose ...
   763  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
   764  		t.Fatal(err)
   765  	}
   766  
   767  	ensureNewProposal(proposalCh, height, round)
   768  
   769  	// go to prevote, prevote for locked block (not proposal)
   770  	ensurePrevote(voteCh, height, round)
   771  	validatePrevote(t, cs1, round, vss[0], lockedBlockHash)
   772  	// now lets add prevotes from everyone else for nil (a polka!)
   773  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
   774  
   775  	// the polka makes us unlock and precommit nil
   776  	ensureNewUnlock(unlockCh, height, round)
   777  	ensurePrecommit(voteCh, height, round)
   778  
   779  	// we should have unlocked and committed nil
   780  	// NOTE: since we don't relock on nil, the lock round is -1
   781  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
   782  
   783  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3)
   784  	ensureNewRound(newRoundCh, height, round+1)
   785  }
   786  
   787  // 4 vals, v1 locks on proposed block in the first round but the other validators only prevote
   788  // In the second round, v1 misses the proposal but sees a majority prevote an unknown block so
   789  // v1 should unlock and precommit nil. In the third round another block is proposed, all vals
   790  // prevote and now v1 can lock onto the third block and precommit that
   791  func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
   792  	cs1, vss := randState(4)
   793  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
   794  	height, round := cs1.Height, cs1.Round
   795  
   796  	partSize := types.BlockPartSizeBytes
   797  
   798  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
   799  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   800  	pv1, err := cs1.privValidator.GetPubKey()
   801  	require.NoError(t, err)
   802  	addr := pv1.Address()
   803  	voteCh := subscribeToVoter(cs1, addr)
   804  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   805  	// everything done from perspective of cs1
   806  
   807  	/*
   808  		Round0 (cs1, A) // A A A A// A nil nil nil
   809  	*/
   810  
   811  	forceProposer(cs1, vss, []int{0, 1, 2}, []int64{height, height, height}, []int32{round, round + 1, round + 2})
   812  
   813  	// start round and wait for propose and prevote
   814  	startTestRound(cs1, height, round)
   815  
   816  	ensureNewRound(newRoundCh, height, round)
   817  	ensureNewProposal(proposalCh, height, round)
   818  	rs := cs1.GetRoundState()
   819  	firstBlockHash := rs.ProposalBlock.Hash()
   820  	firstBlockParts := rs.ProposalBlockParts.Header()
   821  
   822  	ensurePrevote(voteCh, height, round) // prevote
   823  
   824  	signAddVotes(cs1, tmproto.PrevoteType, firstBlockHash, firstBlockParts, vs2, vs3, vs4)
   825  
   826  	ensurePrecommit(voteCh, height, round) // our precommit
   827  	// the proposed block should now be locked and our precommit added
   828  	validatePrecommit(t, cs1, round, round, vss[0], firstBlockHash, firstBlockHash)
   829  
   830  	// add precommits from the rest
   831  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
   832  
   833  	// before we timeout to the new round set the new proposal
   834  	cs2 := newState(cs1.state, vs2, counter.NewApplication(true))
   835  	prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1)
   836  	if prop == nil || propBlock == nil {
   837  		t.Fatal("Failed to create proposal block with vs2")
   838  	}
   839  	secondBlockParts := propBlock.MakePartSet(partSize)
   840  	secondBlockHash := propBlock.Hash()
   841  	require.NotEqual(t, secondBlockHash, firstBlockHash)
   842  
   843  	incrementRound(vs2, vs3, vs4)
   844  
   845  	// timeout to new round
   846  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   847  
   848  	round++ // moving to the next round
   849  
   850  	ensureNewRound(newRoundCh, height, round)
   851  	t.Log("### ONTO ROUND 1")
   852  
   853  	/*
   854  		Round1 (vs2, B) // A B B B // nil nil nil nil)
   855  	*/
   856  
   857  	// now we're on a new round but v1 misses the proposal
   858  
   859  	// go to prevote, node should prevote for locked block (not the new proposal) - this is relocking
   860  	ensurePrevote(voteCh, height, round)
   861  	validatePrevote(t, cs1, round, vss[0], firstBlockHash)
   862  
   863  	// now lets add prevotes from everyone else for the new block
   864  	signAddVotes(cs1, tmproto.PrevoteType, secondBlockHash, secondBlockParts.Header(), vs2, vs3, vs4)
   865  
   866  	ensurePrecommit(voteCh, height, round)
   867  	// we should have unlocked and locked on the new block, sending a precommit for this new block
   868  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
   869  
   870  	if err := cs1.SetProposalAndBlock(prop, propBlock, secondBlockParts, "some peer"); err != nil {
   871  		t.Fatal(err)
   872  	}
   873  
   874  	// more prevote creating a majority on the new block and this is then committed
   875  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
   876  
   877  	// before we timeout to the new round set the new proposal
   878  	cs3 := newState(cs1.state, vs3, counter.NewApplication(true))
   879  	prop, propBlock = decideProposal(cs3, vs3, vs3.Height, vs3.Round+1)
   880  	if prop == nil || propBlock == nil {
   881  		t.Fatal("Failed to create proposal block with vs2")
   882  	}
   883  	thirdPropBlockParts := propBlock.MakePartSet(partSize)
   884  	thirdPropBlockHash := propBlock.Hash()
   885  	require.NotEqual(t, secondBlockHash, thirdPropBlockHash)
   886  
   887  	incrementRound(vs2, vs3, vs4)
   888  
   889  	// timeout to new round
   890  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   891  
   892  	round++ // moving to the next round
   893  	ensureNewRound(newRoundCh, height, round)
   894  	t.Log("### ONTO ROUND 2")
   895  
   896  	/*
   897  		Round2 (vs3, C) // C C C C // C nil nil nil)
   898  	*/
   899  
   900  	if err := cs1.SetProposalAndBlock(prop, propBlock, thirdPropBlockParts, "some peer"); err != nil {
   901  		t.Fatal(err)
   902  	}
   903  
   904  	ensurePrevote(voteCh, height, round)
   905  	// we are no longer locked to the first block so we should be able to prevote
   906  	validatePrevote(t, cs1, round, vss[0], thirdPropBlockHash)
   907  
   908  	signAddVotes(cs1, tmproto.PrevoteType, thirdPropBlockHash, thirdPropBlockParts.Header(), vs2, vs3, vs4)
   909  
   910  	ensurePrecommit(voteCh, height, round)
   911  	// we have a majority, now vs1 can change lock to the third block
   912  	validatePrecommit(t, cs1, round, round, vss[0], thirdPropBlockHash, thirdPropBlockHash)
   913  }
   914  
   915  // 4 vals
   916  // a polka at round 1 but we miss it
   917  // then a polka at round 2 that we lock on
   918  // then we see the polka from round 1 but shouldn't unlock
   919  func TestStateLockPOLSafety1(t *testing.T) {
   920  	cs1, vss := randState(4)
   921  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
   922  	height, round := cs1.Height, cs1.Round
   923  
   924  	partSize := types.BlockPartSizeBytes
   925  
   926  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
   927  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
   928  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
   929  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
   930  	pv1, err := cs1.privValidator.GetPubKey()
   931  	require.NoError(t, err)
   932  	addr := pv1.Address()
   933  	voteCh := subscribeToVoter(cs1, addr)
   934  
   935  	// force the vss[0], vss[1] to become a proposer by turns
   936  	forceProposer(cs1, vss, []int{0, 1, 3}, []int64{height, height, height}, []int32{round, round + 1, round + 2})
   937  
   938  	// start round and wait for propose and prevote
   939  	startTestRound(cs1, cs1.Height, round)
   940  	ensureNewRound(newRoundCh, height, round)
   941  
   942  	ensureNewProposal(proposalCh, height, round)
   943  	rs := cs1.GetRoundState()
   944  	propBlock := rs.ProposalBlock
   945  
   946  	ensurePrevote(voteCh, height, round)
   947  	validatePrevote(t, cs1, round, vss[0], propBlock.Hash())
   948  
   949  	// the others sign a polka but we don't see it
   950  	prevotes := signVotes(tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4)
   951  
   952  	t.Logf("old prop hash %v", fmt.Sprintf("%X", propBlock.Hash()))
   953  
   954  	// we do see them precommit nil
   955  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
   956  
   957  	// cs1 precommit nil
   958  	ensurePrecommit(voteCh, height, round)
   959  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
   960  
   961  	t.Log("### ONTO ROUND 1")
   962  
   963  	prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
   964  	propBlockHash := propBlock.Hash()
   965  	propBlockParts := propBlock.MakePartSet(partSize)
   966  
   967  	incrementRound(vs2, vs3, vs4)
   968  
   969  	round++ // moving to the next round
   970  	ensureNewRound(newRoundCh, height, round)
   971  
   972  	//XXX: this isnt guaranteed to get there before the timeoutPropose ...
   973  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
   974  		t.Fatal(err)
   975  	}
   976  	/*Round2
   977  	// we timeout and prevote our lock
   978  	// a polka happened but we didn't see it!
   979  	*/
   980  
   981  	ensureNewProposal(proposalCh, height, round)
   982  
   983  	rs = cs1.GetRoundState()
   984  
   985  	if rs.LockedBlock != nil {
   986  		panic("we should not be locked!")
   987  	}
   988  	t.Logf("new prop hash %v", fmt.Sprintf("%X", propBlockHash))
   989  
   990  	// go to prevote, prevote for proposal block
   991  	ensurePrevote(voteCh, height, round)
   992  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
   993  
   994  	// now we see the others prevote for it, so we should lock on it
   995  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
   996  
   997  	ensurePrecommit(voteCh, height, round)
   998  	// we should have precommitted
   999  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
  1000  
  1001  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1002  
  1003  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1004  
  1005  	incrementRound(vs2, vs3, vs4)
  1006  	round++ // moving to the next round
  1007  
  1008  	ensureNewRound(newRoundCh, height, round)
  1009  
  1010  	t.Log("### ONTO ROUND 2")
  1011  	/*Round3
  1012  	we see the polka from round 1 but we shouldn't unlock!
  1013  	*/
  1014  
  1015  	// timeout of propose
  1016  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1017  
  1018  	// finish prevote
  1019  	ensurePrevote(voteCh, height, round)
  1020  	// we should prevote what we're locked on
  1021  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1022  
  1023  	newStepCh := subscribe(cs1.eventBus, types.EventQueryNewRoundStep)
  1024  
  1025  	// before prevotes from the previous round are added
  1026  	// add prevotes from the earlier round
  1027  	addVotes(cs1, prevotes...)
  1028  
  1029  	t.Log("Done adding prevotes!")
  1030  
  1031  	ensureNoNewRoundStep(newStepCh)
  1032  }
  1033  
  1034  // 4 vals.
  1035  // polka P0 at R0, P1 at R1, and P2 at R2,
  1036  // we lock on P0 at R0, don't see P1, and unlock using P2 at R2
  1037  // then we should make sure we don't lock using P1
  1038  
  1039  // What we want:
  1040  // dont see P0, lock on P1 at R1, dont unlock using P0 at R2
  1041  func TestStateLockPOLSafety2(t *testing.T) {
  1042  	cs1, vss := randState(4)
  1043  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1044  	height, round := cs1.Height, cs1.Round
  1045  
  1046  	partSize := types.BlockPartSizeBytes
  1047  
  1048  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1049  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1050  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1051  	unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
  1052  	pv1, err := cs1.privValidator.GetPubKey()
  1053  	require.NoError(t, err)
  1054  	addr := pv1.Address()
  1055  	voteCh := subscribeToVoter(cs1, addr)
  1056  
  1057  	// force the vss[0], vss[1] to become a proposer by turns
  1058  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height}, []int32{round, round + 1})
  1059  
  1060  	// the block for R0: gets polkad but we miss it
  1061  	// (even though we signed it, shhh)
  1062  	_, propBlock0 := decideProposal(cs1, vss[0], height, round)
  1063  	propBlockHash0 := propBlock0.Hash()
  1064  	propBlockParts0 := propBlock0.MakePartSet(partSize)
  1065  	propBlockID0 := types.BlockID{Hash: propBlockHash0, PartSetHeader: propBlockParts0.Header()}
  1066  
  1067  	// the others sign a polka but we don't see it
  1068  	prevotes := signVotes(tmproto.PrevoteType, propBlockHash0, propBlockParts0.Header(), vs2, vs3, vs4)
  1069  
  1070  	// the block for round 1
  1071  	prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  1072  	propBlockHash1 := propBlock1.Hash()
  1073  	propBlockParts1 := propBlock1.MakePartSet(partSize)
  1074  
  1075  	incrementRound(vs2, vs3, vs4)
  1076  
  1077  	round++ // moving to the next round
  1078  	t.Log("### ONTO Round 1")
  1079  	// jump in at round 1
  1080  	startTestRound(cs1, height, round)
  1081  	ensureNewRound(newRoundCh, height, round)
  1082  
  1083  	if err := cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer"); err != nil {
  1084  		t.Fatal(err)
  1085  	}
  1086  	ensureNewProposal(proposalCh, height, round)
  1087  
  1088  	ensurePrevote(voteCh, height, round)
  1089  	validatePrevote(t, cs1, round, vss[0], propBlockHash1)
  1090  
  1091  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash1, propBlockParts1.Header(), vs2, vs3, vs4)
  1092  
  1093  	ensurePrecommit(voteCh, height, round)
  1094  	// the proposed block should now be locked and our precommit added
  1095  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash1, propBlockHash1)
  1096  
  1097  	// add precommits from the rest
  1098  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs4)
  1099  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash1, propBlockParts1.Header(), vs3)
  1100  
  1101  	incrementRound(vs2, vs3, vs4)
  1102  
  1103  	// timeout of precommit wait to new round
  1104  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1105  
  1106  	round++ // moving to the next round
  1107  	// in round 2 we see the polkad block from round 0
  1108  	newProp := types.NewProposal(height, round, 0, propBlockID0)
  1109  	p := newProp.ToProto()
  1110  	if err := vs3.SignProposal(config.ChainID(), p); err != nil {
  1111  		t.Fatal(err)
  1112  	}
  1113  
  1114  	newProp.Signature = p.Signature
  1115  
  1116  	if err := cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer"); err != nil {
  1117  		t.Fatal(err)
  1118  	}
  1119  
  1120  	// Add the pol votes
  1121  	addVotes(cs1, prevotes...)
  1122  
  1123  	ensureNewRound(newRoundCh, height, round)
  1124  	t.Log("### ONTO Round 2")
  1125  	/*Round2
  1126  	// now we see the polka from round 1, but we shouldnt unlock
  1127  	*/
  1128  	ensureNewProposal(proposalCh, height, round)
  1129  
  1130  	ensureNoNewUnlock(unlockCh)
  1131  	ensurePrevote(voteCh, height, round)
  1132  	validatePrevote(t, cs1, round, vss[0], propBlockHash1)
  1133  }
  1134  
  1135  // 4 vals.
  1136  // polka P0 at R0 for B0. We lock B0 on P0 at R0. P0 unlocks value at R1.
  1137  
  1138  // What we want:
  1139  // P0 proposes B0 at R3.
  1140  func TestProposeValidBlock(t *testing.T) {
  1141  	cs1, vss := randState(4)
  1142  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1143  	height, round := cs1.Height, cs1.Round
  1144  
  1145  	partSize := types.BlockPartSizeBytes
  1146  
  1147  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1148  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1149  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1150  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1151  	unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
  1152  	pv1, err := cs1.privValidator.GetPubKey()
  1153  	require.NoError(t, err)
  1154  	addr := pv1.Address()
  1155  	voteCh := subscribeToVoter(cs1, addr)
  1156  
  1157  	forceProposer(cs1, vss, []int{0, theOthers(0), theOthers(0), theOthers(0), 0},
  1158  		[]int64{height, height, height, height, height}, []int32{round, round + 1, round + 2, round + 3, round + 4})
  1159  
  1160  	// start round and wait for propose and prevote
  1161  	startTestRound(cs1, cs1.Height, round)
  1162  	ensureNewRound(newRoundCh, height, round)
  1163  
  1164  	ensureNewProposal(proposalCh, height, round)
  1165  	rs := cs1.GetRoundState()
  1166  	propBlock := rs.ProposalBlock
  1167  	propBlockHash := propBlock.Hash()
  1168  
  1169  	ensurePrevote(voteCh, height, round)
  1170  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1171  
  1172  	// the others sign a polka
  1173  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4)
  1174  
  1175  	ensurePrecommit(voteCh, height, round)
  1176  	// we should have precommitted
  1177  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
  1178  
  1179  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1180  
  1181  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1182  
  1183  	incrementRound(vs2, vs3, vs4)
  1184  	round++ // moving to the next round
  1185  
  1186  	ensureNewRound(newRoundCh, height, round)
  1187  
  1188  	t.Log("### ONTO ROUND 2")
  1189  
  1190  	// timeout of propose
  1191  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1192  
  1193  	ensurePrevote(voteCh, height, round)
  1194  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1195  
  1196  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1197  
  1198  	ensureNewUnlock(unlockCh, height, round)
  1199  
  1200  	ensurePrecommit(voteCh, height, round)
  1201  	// we should have precommitted
  1202  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1203  
  1204  	incrementRound(vs2, vs3, vs4)
  1205  	incrementRound(vs2, vs3, vs4)
  1206  
  1207  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1208  
  1209  	round += 2 // moving to the next round
  1210  
  1211  	ensureNewRound(newRoundCh, height, round)
  1212  	t.Log("### ONTO ROUND 3")
  1213  
  1214  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1215  
  1216  	round++ // moving to the next round
  1217  
  1218  	ensureNewRound(newRoundCh, height, round)
  1219  
  1220  	t.Log("### ONTO ROUND 4")
  1221  
  1222  	ensureNewProposal(proposalCh, height, round)
  1223  
  1224  	rs = cs1.GetRoundState()
  1225  	assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), propBlockHash))
  1226  	assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), rs.ValidBlock.Hash()))
  1227  	assert.True(t, rs.Proposal.POLRound == rs.ValidRound)
  1228  	assert.True(t, bytes.Equal(rs.Proposal.BlockID.Hash, rs.ValidBlock.Hash()))
  1229  }
  1230  
  1231  // 4 vals.
  1232  // polka P0 at R0 for B0. We lock B0 on P0 at R0. P0 unlocks value at R1.
  1233  
  1234  // What we want:
  1235  // P0 proposes B0 at R3.
  1236  func TestValidateValidBlockOnCommit(t *testing.T) {
  1237  	cs1, vss := randState(4)
  1238  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1239  	height, round := cs1.Height, cs1.Round
  1240  
  1241  	partSize := types.BlockPartSizeBytes
  1242  
  1243  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1244  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1245  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1246  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1247  	unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
  1248  	pubKey, _ := cs1.privValidator.GetPubKey()
  1249  	addr := pubKey.Address()
  1250  	voteCh := subscribeToVoter(cs1, addr)
  1251  
  1252  	forceProposer(cs1, vss, []int{0, theOthers(0), theOthers(0), theOthers(0), 0},
  1253  		[]int64{height, height, height, height, height}, []int32{round, round + 1, round + 2, round + 3, round + 4})
  1254  
  1255  	// start round and wait for propose and prevote
  1256  	startTestRound(cs1, cs1.Height, round)
  1257  	ensureNewRound(newRoundCh, height, round)
  1258  
  1259  	ensureNewProposal(proposalCh, height, round)
  1260  	rs := cs1.GetRoundState()
  1261  	propBlock := rs.ProposalBlock
  1262  	propBlockHash := propBlock.Hash()
  1263  
  1264  	ensurePrevote(voteCh, height, round)
  1265  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1266  
  1267  	// the others sign a polka
  1268  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4)
  1269  
  1270  	ensurePrecommit(voteCh, height, round)
  1271  	// we should have precommitted
  1272  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
  1273  
  1274  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1275  
  1276  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1277  
  1278  	incrementRound(vs2, vs3, vs4)
  1279  	round++ // moving to the next round
  1280  
  1281  	ensureNewRound(newRoundCh, height, round)
  1282  
  1283  	t.Log("### ONTO ROUND 1")
  1284  
  1285  	// timeout of propose
  1286  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1287  
  1288  	ensurePrevote(voteCh, height, round)
  1289  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1290  
  1291  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1292  
  1293  	ensureNewUnlock(unlockCh, height, round)
  1294  
  1295  	ensurePrecommit(voteCh, height, round)
  1296  	// we should have precommitted
  1297  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1298  
  1299  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1300  
  1301  	incrementRound(vs2, vs3, vs4)
  1302  	round++ // moving to the next round
  1303  	ensureNewRound(newRoundCh, height, round)
  1304  
  1305  	t.Log("### ONTO ROUND 2")
  1306  
  1307  	// timeout of propose
  1308  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1309  
  1310  	ensurePrevote(voteCh, height, round)
  1311  	validatePrevote(t, cs1, round, vss[0], nil)
  1312  
  1313  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1314  
  1315  	ensurePrecommit(voteCh, height, round)
  1316  	// we should have precommitted
  1317  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1318  
  1319  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1320  
  1321  	incrementRound(vs2, vs3, vs4)
  1322  	round++ // moving to the next round
  1323  	ensureNewRound(newRoundCh, height, round)
  1324  
  1325  	t.Log("### ONTO ROUND 3")
  1326  
  1327  	// timeout of propose
  1328  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1329  
  1330  	ensurePrevote(voteCh, height, round)
  1331  	validatePrevote(t, cs1, round, vss[0], nil)
  1332  
  1333  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1334  
  1335  	ensurePrecommit(voteCh, height, round)
  1336  	// we should have precommitted
  1337  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1338  
  1339  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1340  
  1341  	incrementRound(vs2, vs3, vs4)
  1342  	round++ // moving to the next round
  1343  	ensureNewRound(newRoundCh, height, round)
  1344  
  1345  	t.Log("### ONTO ROUND 4")
  1346  
  1347  	ensureNewProposal(proposalCh, height, round)
  1348  
  1349  	rs = cs1.GetRoundState()
  1350  	propBlock = rs.ProposalBlock
  1351  	propBlockHash = propBlock.Hash()
  1352  
  1353  	// current round is 4, proposal block round is 0
  1354  	// validator should verify proposal block made in round 0(valid block)
  1355  	ensurePrevote(voteCh, height, round)
  1356  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1357  
  1358  	// the others sign a polka
  1359  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4)
  1360  
  1361  	ensurePrecommit(voteCh, height, round)
  1362  	// we should have precommitted
  1363  	validatePrecommit(t, cs1, round, round, vss[0], propBlockHash, propBlockHash)
  1364  
  1365  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash, types.PartSetHeader{}, vs2, vs3, vs4)
  1366  
  1367  	rs = cs1.GetRoundState()
  1368  	assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), propBlockHash))
  1369  	assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), rs.ValidBlock.Hash()))
  1370  	assert.True(t, bytes.Equal(rs.Proposal.BlockID.Hash, rs.ValidBlock.Hash()))
  1371  }
  1372  
  1373  // What we want:
  1374  // P0 miss to lock B but set valid block to B after receiving delayed prevote.
  1375  func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
  1376  	cs1, vss := randState(4)
  1377  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1378  	height, round := cs1.Height, cs1.Round
  1379  
  1380  	partSize := types.BlockPartSizeBytes
  1381  
  1382  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1383  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1384  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1385  	validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
  1386  	pv1, err := cs1.privValidator.GetPubKey()
  1387  	require.NoError(t, err)
  1388  	addr := pv1.Address()
  1389  	voteCh := subscribeToVoter(cs1, addr)
  1390  
  1391  	// force the vss[0], vss[1] to become a proposer by turns
  1392  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height}, []int32{round, round + 1})
  1393  
  1394  	// start round and wait for propose and prevote
  1395  	startTestRound(cs1, cs1.Height, round)
  1396  	ensureNewRound(newRoundCh, height, round)
  1397  
  1398  	ensureNewProposal(proposalCh, height, round)
  1399  	rs := cs1.GetRoundState()
  1400  	propBlock := rs.ProposalBlock
  1401  	propBlockHash := propBlock.Hash()
  1402  	propBlockParts := propBlock.MakePartSet(partSize)
  1403  
  1404  	ensurePrevote(voteCh, height, round)
  1405  	validatePrevote(t, cs1, round, vss[0], propBlockHash)
  1406  
  1407  	// vs2 send prevote for propBlock
  1408  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2)
  1409  
  1410  	// vs3 send prevote nil
  1411  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs3)
  1412  
  1413  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
  1414  
  1415  	ensurePrecommit(voteCh, height, round)
  1416  	// we should have precommitted
  1417  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1418  
  1419  	rs = cs1.GetRoundState()
  1420  
  1421  	assert.True(t, rs.ValidBlock == nil)
  1422  	assert.True(t, rs.ValidBlockParts == nil)
  1423  	assert.True(t, rs.ValidRound == -1)
  1424  
  1425  	// vs2 send (delayed) prevote for propBlock
  1426  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs4)
  1427  
  1428  	ensureNewValidBlock(validBlockCh, height, round)
  1429  
  1430  	rs = cs1.GetRoundState()
  1431  
  1432  	assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
  1433  	assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
  1434  	assert.True(t, rs.ValidRound == round)
  1435  }
  1436  
  1437  // What we want:
  1438  // P0 miss to lock B as Proposal Block is missing, but set valid block to B after
  1439  // receiving delayed Block Proposal.
  1440  func TestSetValidBlockOnDelayedProposal(t *testing.T) {
  1441  	cs1, vss := randState(4)
  1442  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1443  	height, round := cs1.Height, cs1.Round
  1444  
  1445  	partSize := types.BlockPartSizeBytes
  1446  
  1447  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1448  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1449  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1450  	validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
  1451  	pv1, err := cs1.privValidator.GetPubKey()
  1452  	require.NoError(t, err)
  1453  	addr := pv1.Address()
  1454  	voteCh := subscribeToVoter(cs1, addr)
  1455  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1456  
  1457  	round++ // move to round in which P0 is not proposer
  1458  	incrementRound(vs2, vs3, vs4)
  1459  
  1460  	// force the vss[0], vss[1] to become a proposer by turns
  1461  	forceProposer(cs1, vss, []int{1, 2}, []int64{height, height}, []int32{round, round + 1})
  1462  
  1463  	startTestRound(cs1, cs1.Height, round)
  1464  	ensureNewRound(newRoundCh, height, round)
  1465  
  1466  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1467  
  1468  	ensurePrevote(voteCh, height, round)
  1469  	validatePrevote(t, cs1, round, vss[0], nil)
  1470  
  1471  	prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
  1472  	propBlockHash := propBlock.Hash()
  1473  	propBlockParts := propBlock.MakePartSet(partSize)
  1474  
  1475  	// vs2, vs3 and vs4 send prevote for propBlock
  1476  	signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
  1477  	ensureNewValidBlock(validBlockCh, height, round)
  1478  
  1479  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds())
  1480  
  1481  	ensurePrecommit(voteCh, height, round)
  1482  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1483  
  1484  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
  1485  		t.Fatal(err)
  1486  	}
  1487  
  1488  	ensureNewProposal(proposalCh, height, round)
  1489  	rs := cs1.GetRoundState()
  1490  
  1491  	assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
  1492  	assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
  1493  	assert.True(t, rs.ValidRound == round)
  1494  }
  1495  
  1496  // 4 vals, 3 Nil Precommits at P0
  1497  // What we want:
  1498  // P0 waits for timeoutPrecommit before starting next round
  1499  func TestWaitingTimeoutOnNilPolka(t *testing.T) {
  1500  	cs1, vss := randState(4)
  1501  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1502  	height, round := cs1.Height, cs1.Round
  1503  
  1504  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1505  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1506  
  1507  	// start round
  1508  	startTestRound(cs1, height, round)
  1509  	ensureNewRound(newRoundCh, height, round)
  1510  
  1511  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1512  
  1513  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1514  	ensureNewRound(newRoundCh, height, round+1)
  1515  }
  1516  
  1517  // 4 vals, 3 Prevotes for nil from the higher round.
  1518  // What we want:
  1519  // P0 waits for timeoutPropose in the next round before entering prevote
  1520  func TestWaitingTimeoutProposeOnNewRound(t *testing.T) {
  1521  	cs1, vss := randState(4)
  1522  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1523  	height, round := cs1.Height, cs1.Round
  1524  
  1525  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1526  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1527  	pv1, err := cs1.privValidator.GetPubKey()
  1528  	require.NoError(t, err)
  1529  	addr := pv1.Address()
  1530  	voteCh := subscribeToVoter(cs1, addr)
  1531  
  1532  	// start round
  1533  	startTestRound(cs1, height, round)
  1534  	ensureNewRound(newRoundCh, height, round)
  1535  
  1536  	ensurePrevote(voteCh, height, round)
  1537  
  1538  	incrementRound(vss[1:]...)
  1539  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1540  
  1541  	round++ // moving to the next round
  1542  	ensureNewRound(newRoundCh, height, round)
  1543  
  1544  	rs := cs1.GetRoundState()
  1545  	assert.True(t, rs.Step == cstypes.RoundStepPropose) // P0 does not prevote before timeoutPropose expires
  1546  
  1547  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1548  
  1549  	ensurePrevote(voteCh, height, round)
  1550  	validatePrevote(t, cs1, round, vss[0], nil)
  1551  }
  1552  
  1553  // 4 vals, 3 Precommits for nil from the higher round.
  1554  // What we want:
  1555  // P0 jump to higher round, precommit and start precommit wait
  1556  func TestRoundSkipOnNilPolkaFromHigherRound(t *testing.T) {
  1557  	cs1, vss := randState(4)
  1558  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1559  	height, round := cs1.Height, cs1.Round
  1560  
  1561  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1562  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1563  	pv1, err := cs1.privValidator.GetPubKey()
  1564  	require.NoError(t, err)
  1565  	addr := pv1.Address()
  1566  	voteCh := subscribeToVoter(cs1, addr)
  1567  
  1568  	// start round
  1569  	startTestRound(cs1, height, round)
  1570  	ensureNewRound(newRoundCh, height, round)
  1571  
  1572  	ensurePrevote(voteCh, height, round)
  1573  
  1574  	incrementRound(vss[1:]...)
  1575  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1576  
  1577  	round++ // moving to the next round
  1578  	ensureNewRound(newRoundCh, height, round)
  1579  
  1580  	ensurePrecommit(voteCh, height, round)
  1581  	validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
  1582  
  1583  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1584  
  1585  	round++ // moving to the next round
  1586  	ensureNewRound(newRoundCh, height, round)
  1587  }
  1588  
  1589  // 4 vals, 3 Prevotes for nil in the current round.
  1590  // What we want:
  1591  // P0 wait for timeoutPropose to expire before sending prevote.
  1592  func TestWaitTimeoutProposeOnNilPolkaForTheCurrentRound(t *testing.T) {
  1593  	cs1, vss := randState(4)
  1594  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1595  	height, round := cs1.Height, int32(1)
  1596  
  1597  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1598  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1599  	pv1, err := cs1.privValidator.GetPubKey()
  1600  	require.NoError(t, err)
  1601  	addr := pv1.Address()
  1602  	voteCh := subscribeToVoter(cs1, addr)
  1603  
  1604  	// start round in which PO is not proposer
  1605  	startTestRound(cs1, height, round)
  1606  	ensureNewRound(newRoundCh, height, round)
  1607  
  1608  	incrementRound(vss[1:]...)
  1609  	signAddVotes(cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4)
  1610  
  1611  	ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
  1612  
  1613  	ensurePrevote(voteCh, height, round)
  1614  	validatePrevote(t, cs1, round, vss[0], nil)
  1615  }
  1616  
  1617  // What we want:
  1618  // P0 emit NewValidBlock event upon receiving 2/3+ Precommit for B but hasn't received block B yet
  1619  func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) {
  1620  	cs1, vss := randState(4)
  1621  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1622  	height, round := cs1.Height, int32(1)
  1623  
  1624  	incrementRound(vs2, vs3, vs4)
  1625  
  1626  	partSize := types.BlockPartSizeBytes
  1627  
  1628  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1629  	validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
  1630  
  1631  	_, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round)
  1632  	propBlockHash := propBlock.Hash()
  1633  	propBlockParts := propBlock.MakePartSet(partSize)
  1634  
  1635  	// start round in which PO is not proposer
  1636  	startTestRound(cs1, height, round)
  1637  	ensureNewRound(newRoundCh, height, round)
  1638  
  1639  	// vs2, vs3 and vs4 send precommit for propBlock
  1640  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
  1641  	ensureNewValidBlock(validBlockCh, height, round)
  1642  
  1643  	rs := cs1.GetRoundState()
  1644  	assert.True(t, rs.Step == cstypes.RoundStepCommit)
  1645  	assert.True(t, rs.ProposalBlock == nil)
  1646  	assert.True(t, rs.ProposalBlockParts.Header().Equals(propBlockParts.Header()))
  1647  
  1648  }
  1649  
  1650  // What we want:
  1651  // P0 receives 2/3+ Precommit for B for round 0, while being in round 1. It emits NewValidBlock event.
  1652  // After receiving block, it executes block and moves to the next height.
  1653  func TestCommitFromPreviousRound(t *testing.T) {
  1654  	cs1, vss := randState(4)
  1655  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1656  	height, round := cs1.Height, int32(1)
  1657  
  1658  	partSize := types.BlockPartSizeBytes
  1659  
  1660  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1661  	validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
  1662  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1663  
  1664  	forceProposer(cs1, vss, []int{1, 1, 2}, []int64{height, height, height + 1}, []int32{0, round, 0})
  1665  	prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round)
  1666  	propBlockHash := propBlock.Hash()
  1667  	propBlockParts := propBlock.MakePartSet(partSize)
  1668  
  1669  	// start round in which PO is not proposer
  1670  	startTestRound(cs1, height, round)
  1671  	ensureNewRound(newRoundCh, height, round)
  1672  
  1673  	// vs2, vs3 and vs4 send precommit for propBlock for the previous round
  1674  	signAddVotes(cs1, tmproto.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
  1675  
  1676  	ensureNewValidBlock(validBlockCh, height, round)
  1677  
  1678  	rs := cs1.GetRoundState()
  1679  	assert.True(t, rs.Step == cstypes.RoundStepCommit)
  1680  	assert.True(t, rs.CommitRound == vs2.Round)
  1681  	assert.True(t, rs.ProposalBlock == nil)
  1682  	assert.True(t, rs.ProposalBlockParts.Header().Equals(propBlockParts.Header()))
  1683  
  1684  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
  1685  		t.Fatal(err)
  1686  	}
  1687  
  1688  	ensureNewProposal(proposalCh, height, round)
  1689  	ensureNewRound(newRoundCh, height+1, 0)
  1690  }
  1691  
  1692  type fakeTxNotifier struct {
  1693  	ch chan struct{}
  1694  }
  1695  
  1696  func (n *fakeTxNotifier) TxsAvailable() <-chan struct{} {
  1697  	return n.ch
  1698  }
  1699  
  1700  func (n *fakeTxNotifier) Notify() {
  1701  	n.ch <- struct{}{}
  1702  }
  1703  
  1704  // 2 vals precommit votes for a block but node times out waiting for the third. Move to next round
  1705  // and third precommit arrives which leads to the commit of that header and the correct
  1706  // start of the next round
  1707  func TestStartNextHeightCorrectlyAfterTimeout(t *testing.T) {
  1708  	config.Consensus.SkipTimeoutCommit = false
  1709  	cs1, vss := randState(4)
  1710  	cs1.txNotifier = &fakeTxNotifier{ch: make(chan struct{})}
  1711  
  1712  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1713  	height, round := cs1.Height, cs1.Round
  1714  
  1715  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1716  	timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
  1717  	precommitTimeoutCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1718  
  1719  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1720  	newBlockHeader := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
  1721  	pv1, err := cs1.privValidator.GetPubKey()
  1722  	require.NoError(t, err)
  1723  	addr := pv1.Address()
  1724  	voteCh := subscribeToVoter(cs1, addr)
  1725  
  1726  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height + 1}, []int32{round, 0})
  1727  
  1728  	// start round and wait for propose and prevote
  1729  	startTestRound(cs1, height, round)
  1730  	ensureNewRound(newRoundCh, height, round)
  1731  
  1732  	ensureNewProposal(proposalCh, height, round)
  1733  	rs := cs1.GetRoundState()
  1734  	theBlockHash := rs.ProposalBlock.Hash()
  1735  	theBlockParts := rs.ProposalBlockParts.Header()
  1736  
  1737  	ensurePrevote(voteCh, height, round)
  1738  	validatePrevote(t, cs1, round, vss[0], theBlockHash)
  1739  
  1740  	signAddVotes(cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
  1741  
  1742  	ensurePrecommit(voteCh, height, round)
  1743  	// the proposed block should now be locked and our precommit added
  1744  	validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
  1745  
  1746  	// add precommits
  1747  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2)
  1748  	signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3)
  1749  
  1750  	// wait till timeout occurs
  1751  	ensurePrecommitTimeout(precommitTimeoutCh)
  1752  
  1753  	ensureNewRound(newRoundCh, height, round+1)
  1754  
  1755  	// majority is now reached
  1756  	signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs4)
  1757  
  1758  	ensureNewBlockHeader(newBlockHeader, height, theBlockHash)
  1759  
  1760  	cs1.txNotifier.(*fakeTxNotifier).Notify()
  1761  
  1762  	ensureNewTimeout(timeoutProposeCh, height+1, round, cs1.config.Propose(round).Nanoseconds())
  1763  	rs = cs1.GetRoundState()
  1764  	assert.False(
  1765  		t,
  1766  		rs.TriggeredTimeoutPrecommit,
  1767  		"triggeredTimeoutPrecommit should be false at the beginning of each round")
  1768  }
  1769  
  1770  func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) {
  1771  	config.Consensus.SkipTimeoutCommit = false
  1772  	cs1, vss := randState(4)
  1773  
  1774  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1775  	height, round := cs1.Height, cs1.Round
  1776  
  1777  	partSize := types.BlockPartSizeBytes
  1778  
  1779  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1780  
  1781  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1782  	newBlockHeader := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
  1783  	pv1, err := cs1.privValidator.GetPubKey()
  1784  	require.NoError(t, err)
  1785  	addr := pv1.Address()
  1786  	voteCh := subscribeToVoter(cs1, addr)
  1787  
  1788  	// force the vss[0] to become a proposer
  1789  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height + 1}, []int32{round, 0})
  1790  
  1791  	// start round and wait for propose and prevote
  1792  	startTestRound(cs1, height, round)
  1793  	ensureNewRound(newRoundCh, height, round)
  1794  
  1795  	ensureNewProposal(proposalCh, height, round)
  1796  	rs := cs1.GetRoundState()
  1797  	theBlockHash := rs.ProposalBlock.Hash()
  1798  	theBlockParts := rs.ProposalBlockParts.Header()
  1799  
  1800  	ensurePrevote(voteCh, height, round)
  1801  	validatePrevote(t, cs1, round, vss[0], theBlockHash)
  1802  
  1803  	signAddVotes(cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4)
  1804  
  1805  	ensurePrecommit(voteCh, height, round)
  1806  	validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash)
  1807  
  1808  	// add precommits
  1809  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2)
  1810  	signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3)
  1811  	signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs4)
  1812  
  1813  	ensureNewBlockHeader(newBlockHeader, height, theBlockHash)
  1814  
  1815  	prop, propBlock := decideProposal(cs1, vs2, height+1, 0)
  1816  	propBlockParts := propBlock.MakePartSet(partSize)
  1817  
  1818  	if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
  1819  		t.Fatal(err)
  1820  	}
  1821  	ensureNewProposal(proposalCh, height+1, 0)
  1822  
  1823  	rs = cs1.GetRoundState()
  1824  	assert.False(
  1825  		t,
  1826  		rs.TriggeredTimeoutPrecommit,
  1827  		"triggeredTimeoutPrecommit should be false at the beginning of each height")
  1828  }
  1829  
  1830  //------------------------------------------------------------------------------------------
  1831  // SlashingSuite
  1832  // TODO: Slashing
  1833  
  1834  /*
  1835  func TestStateSlashingPrevotes(t *testing.T) {
  1836  	cs1, vss := randState(2)
  1837  	vs2 := vss[1]
  1838  
  1839  
  1840  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1841  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1842  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1843  	voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  1844  
  1845  	// start round and wait for propose and prevote
  1846  	startTestRound(cs1, cs1.Height, 0)
  1847  	<-newRoundCh
  1848  	re := <-proposalCh
  1849  	<-voteCh // prevote
  1850  
  1851  	rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
  1852  
  1853  	// we should now be stuck in limbo forever, waiting for more prevotes
  1854  	// add one for a different block should cause us to go into prevote wait
  1855  	hash := rs.ProposalBlock.Hash()
  1856  	hash[0] = byte(hash[0]+1) % 255
  1857  	signAddVotes(cs1, tmproto.PrevoteType, hash, rs.ProposalBlockParts.Header(), vs2)
  1858  
  1859  	<-timeoutWaitCh
  1860  
  1861  	// NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  1862  	// away and ignore more prevotes (and thus fail to slash!)
  1863  
  1864  	// add the conflicting vote
  1865  	signAddVotes(cs1, tmproto.PrevoteType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  1866  
  1867  	// XXX: Check for existence of Dupeout info
  1868  }
  1869  
  1870  func TestStateSlashingPrecommits(t *testing.T) {
  1871  	cs1, vss := randState(2)
  1872  	vs2 := vss[1]
  1873  
  1874  
  1875  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1876  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1877  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1878  	voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
  1879  
  1880  	// start round and wait for propose and prevote
  1881  	startTestRound(cs1, cs1.Height, 0)
  1882  	<-newRoundCh
  1883  	re := <-proposalCh
  1884  	<-voteCh // prevote
  1885  
  1886  	// add prevote from vs2
  1887  	signAddVotes(cs1, tmproto.PrevoteType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  1888  
  1889  	<-voteCh // precommit
  1890  
  1891  	// we should now be stuck in limbo forever, waiting for more prevotes
  1892  	// add one for a different block should cause us to go into prevote wait
  1893  	hash := rs.ProposalBlock.Hash()
  1894  	hash[0] = byte(hash[0]+1) % 255
  1895  	signAddVotes(cs1, tmproto.PrecommitType, hash, rs.ProposalBlockParts.Header(), vs2)
  1896  
  1897  	// NOTE: we have to send the vote for different block first so we don't just go into precommit round right
  1898  	// away and ignore more prevotes (and thus fail to slash!)
  1899  
  1900  	// add precommit from vs2
  1901  	signAddVotes(cs1, tmproto.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vs2)
  1902  
  1903  	// XXX: Check for existence of Dupeout info
  1904  }
  1905  */
  1906  
  1907  //------------------------------------------------------------------------------------------
  1908  // CatchupSuite
  1909  
  1910  //------------------------------------------------------------------------------------------
  1911  // HaltSuite
  1912  
  1913  // 4 vals.
  1914  // we receive a final precommit after going into next round, but others might have gone to commit already!
  1915  func TestStateHalt1(t *testing.T) {
  1916  	cs1, vss := randState(4)
  1917  	vs2, vs3, vs4 := vss[1], vss[2], vss[3]
  1918  	height, round := cs1.Height, cs1.Round
  1919  	partSize := types.BlockPartSizeBytes
  1920  
  1921  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  1922  	timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
  1923  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  1924  	newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
  1925  	pv1, err := cs1.privValidator.GetPubKey()
  1926  	require.NoError(t, err)
  1927  	addr := pv1.Address()
  1928  	voteCh := subscribeToVoter(cs1, addr)
  1929  
  1930  	forceProposer(cs1, vss, []int{0, 1}, []int64{height, height}, []int32{round, round + 1})
  1931  
  1932  	// start round and wait for propose and prevote
  1933  	startTestRound(cs1, height, round)
  1934  	ensureNewRound(newRoundCh, height, round)
  1935  
  1936  	ensureNewProposal(proposalCh, height, round)
  1937  	rs := cs1.GetRoundState()
  1938  	propBlock := rs.ProposalBlock
  1939  	propBlockParts := propBlock.MakePartSet(partSize)
  1940  
  1941  	ensurePrevote(voteCh, height, round)
  1942  
  1943  	signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlockParts.Header(), vs2, vs3, vs4)
  1944  
  1945  	ensurePrecommit(voteCh, height, round)
  1946  	// the proposed block should now be locked and our precommit added
  1947  	validatePrecommit(t, cs1, round, round, vss[0], propBlock.Hash(), propBlock.Hash())
  1948  
  1949  	// add precommits from the rest
  1950  	signAddVotes(cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2) // didnt receive proposal
  1951  	signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlockParts.Header(), vs3)
  1952  	// we receive this later, but vs3 might receive it earlier and with ours will go to commit!
  1953  	precommit4 := signVote(vs4, tmproto.PrecommitType, propBlock.Hash(), propBlockParts.Header())
  1954  
  1955  	incrementRound(vs2, vs3, vs4)
  1956  
  1957  	// timeout to new round
  1958  	ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds())
  1959  
  1960  	round++ // moving to the next round
  1961  
  1962  	ensureNewRound(newRoundCh, height, round)
  1963  	rs = cs1.GetRoundState()
  1964  
  1965  	t.Log("### ONTO ROUND 1")
  1966  	/*Round2
  1967  	// we timeout and prevote our lock
  1968  	// a polka happened but we didn't see it!
  1969  	*/
  1970  
  1971  	// go to prevote, prevote for locked block
  1972  	ensurePrevote(voteCh, height, round)
  1973  	validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash())
  1974  
  1975  	// now we receive the precommit from the previous round
  1976  	addVotes(cs1, precommit4)
  1977  
  1978  	// receiving that precommit should take us straight to commit
  1979  	ensureNewBlock(newBlockCh, height)
  1980  
  1981  	ensureNewRound(newRoundCh, height+1, 0)
  1982  }
  1983  
  1984  func TestStateOutputsBlockPartsStats(t *testing.T) {
  1985  	// create dummy peer
  1986  	cs, _ := randState(1)
  1987  	peer := p2pmock.NewPeer(nil)
  1988  
  1989  	// 1) new block part
  1990  	parts := types.NewPartSetFromData(tmrand.Bytes(100), 10)
  1991  	msg := &BlockPartMessage{
  1992  		Height: 1,
  1993  		Round:  0,
  1994  		Part:   parts.GetPart(0),
  1995  	}
  1996  
  1997  	cs.ProposalBlockParts = types.NewPartSetFromHeader(parts.Header())
  1998  	cs.handleMsg(msgInfo{msg, peer.ID()})
  1999  
  2000  	statsMessage := <-cs.statsMsgQueue
  2001  	require.Equal(t, msg, statsMessage.Msg, "")
  2002  	require.Equal(t, peer.ID(), statsMessage.PeerID, "")
  2003  
  2004  	// sending the same part from different peer
  2005  	cs.handleMsg(msgInfo{msg, "peer2"})
  2006  
  2007  	// sending the part with the same height, but different round
  2008  	msg.Round = 1
  2009  	cs.handleMsg(msgInfo{msg, peer.ID()})
  2010  
  2011  	// sending the part from the smaller height
  2012  	msg.Height = 0
  2013  	cs.handleMsg(msgInfo{msg, peer.ID()})
  2014  
  2015  	// sending the part from the bigger height
  2016  	msg.Height = 3
  2017  	cs.handleMsg(msgInfo{msg, peer.ID()})
  2018  
  2019  	select {
  2020  	case <-cs.statsMsgQueue:
  2021  		t.Errorf("should not output stats message after receiving the known block part!")
  2022  	case <-time.After(50 * time.Millisecond):
  2023  	}
  2024  
  2025  }
  2026  
  2027  func TestStateOutputVoteStats(t *testing.T) {
  2028  	cs, vss := randState(2)
  2029  	// create dummy peer
  2030  	peer := p2pmock.NewPeer(nil)
  2031  
  2032  	randBytes := tmrand.Bytes(tmhash.Size)
  2033  
  2034  	vote := signVote(vss[1], tmproto.PrecommitType, randBytes, types.PartSetHeader{})
  2035  
  2036  	voteMessage := &VoteMessage{vote}
  2037  	cs.handleMsg(msgInfo{voteMessage, peer.ID()})
  2038  
  2039  	statsMessage := <-cs.statsMsgQueue
  2040  	require.Equal(t, voteMessage, statsMessage.Msg, "")
  2041  	require.Equal(t, peer.ID(), statsMessage.PeerID, "")
  2042  
  2043  	// sending the same part from different peer
  2044  	cs.handleMsg(msgInfo{&VoteMessage{vote}, "peer2"})
  2045  
  2046  	// sending the vote for the bigger height
  2047  	incrementHeight(vss[1])
  2048  	vote = signVote(vss[1], tmproto.PrecommitType, randBytes, types.PartSetHeader{})
  2049  
  2050  	cs.handleMsg(msgInfo{&VoteMessage{vote}, peer.ID()})
  2051  
  2052  	select {
  2053  	case <-cs.statsMsgQueue:
  2054  		t.Errorf("should not output stats message after receiving the known vote or vote from bigger height")
  2055  	case <-time.After(50 * time.Millisecond):
  2056  	}
  2057  
  2058  }
  2059  
  2060  func TestSignSameVoteTwice(t *testing.T) {
  2061  	_, vss := randState(2)
  2062  
  2063  	randBytes := tmrand.Bytes(tmhash.Size)
  2064  
  2065  	vote := signVote(vss[1],
  2066  		tmproto.PrecommitType,
  2067  		randBytes,
  2068  		types.PartSetHeader{Total: 10, Hash: randBytes},
  2069  	)
  2070  
  2071  	vote2 := signVote(vss[1],
  2072  		tmproto.PrecommitType,
  2073  		randBytes,
  2074  		types.PartSetHeader{Total: 10, Hash: randBytes},
  2075  	)
  2076  
  2077  	require.Equal(t, vote, vote2)
  2078  }
  2079  
  2080  // subscribe subscribes test client to the given query and returns a channel with cap = 1.
  2081  func subscribe(eventBus *types.EventBus, q tmpubsub.Query) <-chan tmpubsub.Message {
  2082  	sub, err := eventBus.Subscribe(context.Background(), testSubscriber, q)
  2083  	if err != nil {
  2084  		panic(fmt.Sprintf("failed to subscribe %s to %v", testSubscriber, q))
  2085  	}
  2086  	return sub.Out()
  2087  }
  2088  
  2089  // subscribe subscribes test client to the given query and returns a channel with cap = 0.
  2090  func subscribeUnBuffered(eventBus *types.EventBus, q tmpubsub.Query) <-chan tmpubsub.Message {
  2091  	sub, err := eventBus.SubscribeUnbuffered(context.Background(), testSubscriber, q)
  2092  	if err != nil {
  2093  		panic(fmt.Sprintf("failed to subscribe %s to %v", testSubscriber, q))
  2094  	}
  2095  	return sub.Out()
  2096  }
  2097  
  2098  func TestPruneBlocks(t *testing.T) {
  2099  	// Based behaviour is counter.Application
  2100  	mockApp := &mocks.Application{}
  2101  	mockApp.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
  2102  	mockApp.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{})
  2103  	mockApp.On("BeginRecheckTx", mock.Anything).Return(ocabci.ResponseBeginRecheckTx{Code: ocabci.CodeTypeOK})
  2104  	mockApp.On("EndRecheckTx", mock.Anything).Return(ocabci.ResponseEndRecheckTx{Code: ocabci.CodeTypeOK})
  2105  	// Mocking behaviour to response `RetainHeight` for pruneBlocks
  2106  	mockApp.On("Commit", mock.Anything, mock.Anything).Return(abci.ResponseCommit{RetainHeight: 1})
  2107  
  2108  	cs1, vss := randStateWithApp(4, mockApp)
  2109  	height, round := cs1.Height, cs1.Round
  2110  
  2111  	newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
  2112  	proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
  2113  
  2114  	startTestRound(cs1, height, round)
  2115  
  2116  	// Wait for new round so proposer is set.
  2117  	ensureNewRound(newRoundCh, height, round)
  2118  
  2119  	// Wait for complete proposal.
  2120  	ensureNewProposal(proposalCh, height, round)
  2121  
  2122  	rs := cs1.GetRoundState()
  2123  	signAddVotes(cs1, tmproto.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
  2124  
  2125  	// Wait for new round so next validator is set.
  2126  	ensureNewRound(newRoundCh, height+1, 0)
  2127  }