From eec74413e70366a7a566464367d81dba645293a8 Mon Sep 17 00:00:00 2001 From: William Banfield Date: Thu, 23 Sep 2021 19:07:48 -0400 Subject: [PATCH] state_test.go fixes to accomodate prevoting for nil --- internal/consensus/state_test.go | 76 ++++++++++++++------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 893cf2add..c24d129c3 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -458,8 +458,8 @@ func TestStateLock_NoPOL(t *testing.T) { signAddVotes(config, cs1, tmproto.PrevoteType, theBlockHash, thePartSetHeader, vs2) ensurePrevote(t, voteCh, height, round) // prevote - ensurePrecommit(t, voteCh, height, round) // precommit // the proposed block should now be locked and our precommit added + ensurePrecommit(t, voteCh, height, round) validatePrecommit(t, cs1, round, round, vss[0], theBlockHash, theBlockHash) // we should now be stuck in limbo forever, waiting for more precommits @@ -491,13 +491,12 @@ func TestStateLock_NoPOL(t *testing.T) { rs := cs1.GetRoundState() if rs.ProposalBlock != nil { - panic("Expected proposal block to be nil") + t.Fatal("Expected proposal block to be nil") } - // wait to finish prevote + // we should have prevoted nil since we did not see a proposal in the round. ensurePrevote(t, voteCh, height, round) - // we should have prevoted our locked block - validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash()) + validatePrevote(t, cs1, round, vss[0], nil) // add a conflicting prevote from the other validator signAddVotes(config, cs1, tmproto.PrevoteType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2) @@ -507,9 +506,9 @@ func TestStateLock_NoPOL(t *testing.T) { // and then prevote wait, which should timeout. then wait for precommit ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds()) - ensurePrecommit(t, voteCh, height, round) // precommit - // the proposed block should still be locked and our precommit added - // we should precommit nil and be locked on the proposal + // the proposed block should still be locked block. + // we should precommit nil and be locked on the proposal. + ensurePrecommit(t, voteCh, height, round) validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // add conflicting precommit from vs2 @@ -585,9 +584,10 @@ func TestStateLock_NoPOL(t *testing.T) { } ensureNewProposal(t, proposalCh, height, round) - ensurePrevote(t, voteCh, height, round) // prevote - // prevote for locked block (not proposal) - validatePrevote(t, cs1, 3, vss[0], cs1.LockedBlock.Hash()) + + // prevote for nil since we did not see a proposal for our locked block in the round. + ensurePrevote(t, voteCh, height, round) + validatePrevote(t, cs1, 3, vss[0], nil) // prevote for proposed block signAddVotes(config, cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) @@ -692,11 +692,9 @@ func TestStateLock_POLUpdateLock(t *testing.T) { // ensure that the validator receives the proposal. ensureNewProposal(t, proposalCh, height, round) - // Prevote our locked block. - // TODO: Ensure we prevote for the proposal if it is valid and from a round greater than - // the valid round: https://github.com/tendermint/tendermint/issues/6850. + // Prevote our nil since the proposal does not match our locked block. ensurePrevote(t, voteCh, height, round) - validatePrevote(t, cs1, round, vss[0], theBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) // Add prevotes from the remainder of the validators for the new locked block. signAddVotes(config, cs1, tmproto.PrevoteType, propBlockR1Hash, propBlockR1Parts.Header(), vs2, vs3, vs4) @@ -721,8 +719,6 @@ func TestStateLock_POLRelock(t *testing.T) { vs2, vs3, vs4 := vss[1], vss[2], vss[3] height, round := cs1.Height, cs1.Round - //partSize := types.BlockPartSizeBytes - timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) pv1, err := cs1.privValidator.GetPubKey(context.Background()) @@ -796,9 +792,7 @@ func TestStateLock_POLRelock(t *testing.T) { // ensure that the validator receives the proposal. ensureNewProposal(t, proposalCh, height, round) - // Prevote our locked block. - // TODO: Ensure we prevote for the proposal if it is valid and from a round greater than - // the valid round: https://github.com/tendermint/tendermint/issues/6850. + // Prevote our locked block since it matches the propsal seen in this round. ensurePrevote(t, voteCh, height, round) validatePrevote(t, cs1, round, vss[0], theBlockHash) @@ -1028,7 +1022,7 @@ func TestStateLock_POLDoesNotUnlock(t *testing.T) { theBlockParts := rs.ProposalBlockParts.Header() ensurePrevote(t, voteCh, height, round) - validatePrevote(t, cs1, round, vss[0], theBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) signAddVotes(config, cs1, tmproto.PrevoteType, theBlockHash, theBlockParts, vs2, vs3, vs4) @@ -1060,8 +1054,10 @@ func TestStateLock_POLDoesNotUnlock(t *testing.T) { t.Log("#### ONTO ROUND 1") round++ incrementRound(vs2, vs3, vs4) - prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round) + cs2 := newState(cs1.state, vs2, kvstore.NewApplication()) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round) propBlockParts := propBlock.MakePartSet(types.BlockPartSizeBytes) + require.NotEqual(t, propBlock.Hash(), theBlockHash) if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, ""); err != nil { t.Fatal(err) } @@ -1070,12 +1066,10 @@ func TestStateLock_POLDoesNotUnlock(t *testing.T) { ensureNewProposal(t, proposalCh, height, round) - // prevote for the locked block. We do not currently prevote for the - // proposal. - // TODO: do not prevote the locked block if it does not match the proposal. - // (https://github.com/tendermint/tendermint/issues/6850) + // Prevote for nil since the proposed block does not match our locked block. ensurePrevote(t, voteCh, height, round) - validatePrevote(t, cs1, round, vss[0], theBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) + // add >2/3 prevotes for nil from all other validators signAddVotes(config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4) @@ -1096,7 +1090,8 @@ func TestStateLock_POLDoesNotUnlock(t *testing.T) { t.Log("#### ONTO ROUND 2") round++ incrementRound(vs2, vs3, vs4) - prop, propBlock = decideProposal(t, cs1, vs3, vs3.Height, vs3.Round) + cs3 := newState(cs1.state, vs2, kvstore.NewApplication()) + prop, propBlock = decideProposal(t, cs3, vs3, vs3.Height, vs3.Round) propBlockParts = propBlock.MakePartSet(types.BlockPartSizeBytes) if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, ""); err != nil { t.Fatal(err) @@ -1106,8 +1101,9 @@ func TestStateLock_POLDoesNotUnlock(t *testing.T) { ensureNewProposal(t, proposalCh, height, round) + // Prevote for nil since the proposal does not match our locked block. ensurePrevote(t, voteCh, height, round) - validatePrevote(t, cs1, round, vss[0], theBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) signAddVotes(config, cs1, tmproto.PrevoteType, nil, types.PartSetHeader{}, vs2, vs3, vs4) @@ -1189,9 +1185,9 @@ func TestStateLock_MissingProposalWhenPOLSeenDoesNotUpdateLock(t *testing.T) { ensureNewRound(t, newRoundCh, height, round) - // go to prevote, node should prevote for locked block (not the new proposal) - this is relocking + // prevote for nil since the proposal was not seen. ensurePrevote(t, voteCh, height, round) - validatePrevote(t, cs1, round, vss[0], firstBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) // now lets add prevotes from everyone else for the new block signAddVotes(config, cs1, tmproto.PrevoteType, secondBlockHash, secondBlockParts.Header(), vs2, vs3, vs4) @@ -1312,8 +1308,6 @@ func TestStateLock_POLSafety1(t *testing.T) { propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4) - t.Logf("old prop hash %v", fmt.Sprintf("%X", propBlock.Hash())) - // we do see them precommit nil signAddVotes(config, cs1, tmproto.PrecommitType, nil, types.PartSetHeader{}, vs2, vs3, vs4) @@ -1322,14 +1316,13 @@ func TestStateLock_POLSafety1(t *testing.T) { ensureNewTimeout(t, timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds()) t.Log("### ONTO ROUND 1") - - prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) + incrementRound(vs2, vs3, vs4) + round++ // moving to the next round + cs2 := newState(cs1.state, vs2, kvstore.NewApplication()) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() propBlockParts := propBlock.MakePartSet(partSize) - incrementRound(vs2, vs3, vs4) - - round++ // moving to the next round ensureNewRound(t, newRoundCh, height, round) //XXX: this isnt guaranteed to get there before the timeoutPropose ... @@ -1346,9 +1339,8 @@ func TestStateLock_POLSafety1(t *testing.T) { rs = cs1.GetRoundState() if rs.LockedBlock != nil { - panic("we should not be locked!") + t.Fatalf("was not expected to be locked on a block") } - t.Logf("new prop hash %v", fmt.Sprintf("%X", propBlockHash)) // go to prevote, prevote for proposal block ensurePrevote(t, voteCh, height, round) @@ -1381,7 +1373,7 @@ func TestStateLock_POLSafety1(t *testing.T) { // finish prevote ensurePrevote(t, voteCh, height, round) // we should prevote what we're locked on - validatePrevote(t, cs1, round, vss[0], propBlockHash) + validatePrevote(t, cs1, round, vss[0], nil) newStepCh := subscribe(cs1.eventBus, types.EventQueryNewRoundStep) @@ -1389,8 +1381,6 @@ func TestStateLock_POLSafety1(t *testing.T) { // add prevotes from the earlier round addVotes(cs1, prevotes...) - t.Log("Done adding prevotes!") - ensureNoNewRoundStep(t, newStepCh) }