github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/consensus/state_test.go (about)

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