github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/consensus/state_test.go (about)

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