Browse Source

consensus: Wait timeout precommit before starting new round (#2493)

* Disable transitioning to new round upon 2/3+ of Precommit nils

Pull in ensureVote test function from https://github.com/tendermint/tendermint/pull/2132

* Add several ensureX test methods to wrap channel read with timeout

* Revert panic in tests
pull/2541/head
Zarko Milosevic 6 years ago
committed by Ethan Buchman
parent
commit
12675ecd92
10 changed files with 224 additions and 139 deletions
  1. +2
    -0
      CHANGELOG_PENDING.md
  2. +3
    -3
      config/config.go
  3. +80
    -8
      consensus/common_test.go
  4. +1
    -1
      consensus/reactor.go
  5. +7
    -14
      consensus/state.go
  6. +127
    -110
      consensus/state_test.go
  7. +1
    -0
      lite/dynamic_verifier_test.go
  8. +1
    -1
      p2p/conn/connection.go
  9. +1
    -1
      p2p/peer.go
  10. +1
    -1
      p2p/test_util.go

+ 2
- 0
CHANGELOG_PENDING.md View File

@ -40,6 +40,8 @@ IMPROVEMENTS:
BUG FIXES:
- [autofile] \#2428 Group.RotateFile need call Flush() before rename (@goolAdapter)
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) wait for
timeoutPrecommit before starting next round
- [evidence] \#2515 fix db iter leak (@goolAdapter)
- [common/bit_array] Fixed a bug in the `Or` function
- [common/bit_array] Fixed a bug in the `Sub` function (@bradyjoestar)

+ 3
- 3
config/config.go View File

@ -475,9 +475,9 @@ type MempoolConfig struct {
// DefaultMempoolConfig returns a default configuration for the Tendermint mempool
func DefaultMempoolConfig() *MempoolConfig {
return &MempoolConfig{
Recheck: true,
Broadcast: true,
WalPath: "",
Recheck: true,
Broadcast: true,
WalPath: "",
// Each signature verification takes .5ms, size reduced until we implement
// ABCI Recheck
Size: 5000,


+ 80
- 8
consensus/common_test.go View File

@ -7,6 +7,7 @@ import (
"io/ioutil"
"os"
"path"
"reflect"
"sort"
"sync"
"testing"
@ -306,23 +307,94 @@ func randConsensusState(nValidators int) (*ConsensusState, []*validatorStub) {
//-------------------------------------------------------------------------------
func ensureNoNewEvent(ch <-chan interface{}, timeout time.Duration,
errorMessage string) {
select {
case <-time.After(timeout):
break
case <-ch:
panic(errorMessage)
}
}
func ensureNoNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
ensureNoNewEvent(stepCh, ensureTimeout, "We should be stuck waiting, "+
"not moving to the next step")
}
func ensureNoNewTimeout(stepCh <-chan interface{}, timeout int64) {
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
ensureNoNewEvent(stepCh, timeoutDuration, "We should be stuck waiting, "+
"not moving to the next step")
}
func ensureNewEvent(ch <-chan interface{}, timeout time.Duration, errorMessage string) {
select {
case <-timer.C:
case <-time.After(timeout):
panic(errorMessage)
case <-ch:
break
case <-stepCh:
panic("We should be stuck waiting, not moving to the next step")
}
}
func ensureNewStep(stepCh <-chan interface{}) {
timer := time.NewTimer(ensureTimeout)
ensureNewEvent(stepCh, ensureTimeout,
"Timeout expired while waiting for NewStep event")
}
func ensureNewRound(roundCh <-chan interface{}) {
ensureNewEvent(roundCh, ensureTimeout,
"Timeout expired while waiting for NewRound event")
}
func ensureNewTimeout(timeoutCh <-chan interface{}, timeout int64) {
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
ensureNewEvent(timeoutCh, timeoutDuration,
"Timeout expired while waiting for NewTimeout event")
}
func ensureNewProposal(proposalCh <-chan interface{}) {
ensureNewEvent(proposalCh, ensureTimeout,
"Timeout expired while waiting for NewProposal event")
}
func ensureNewBlock(blockCh <-chan interface{}) {
ensureNewEvent(blockCh, ensureTimeout,
"Timeout expired while waiting for NewBlock event")
}
func ensureNewVote(voteCh <-chan interface{}) {
ensureNewEvent(voteCh, ensureTimeout,
"Timeout expired while waiting for NewVote event")
}
func ensureNewUnlock(unlockCh <-chan interface{}) {
ensureNewEvent(unlockCh, ensureTimeout,
"Timeout expired while waiting for NewUnlock event")
}
func ensureVote(voteCh chan interface{}, height int64, round int,
voteType byte) {
select {
case <-timer.C:
panic("We shouldnt be stuck waiting")
case <-stepCh:
case <-time.After(ensureTimeout):
break
case v := <-voteCh:
edv, ok := v.(types.EventDataVote)
if !ok {
panic(fmt.Sprintf("expected a *types.Vote, "+
"got %v. wrong subscription channel?",
reflect.TypeOf(v)))
}
vote := edv.Vote
if vote.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, vote.Height))
}
if vote.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, vote.Round))
}
if vote.Type != voteType {
panic(fmt.Sprintf("expected type %v, got %v", voteType, vote.Type))
}
}
}


+ 1
- 1
consensus/reactor.go View File

@ -55,7 +55,7 @@ func NewConsensusReactor(consensusState *ConsensusState, fastSync bool, options
conR := &ConsensusReactor{
conS: consensusState,
fastSync: fastSync,
metrics: NopMetrics(),
metrics: NopMetrics(),
}
conR.updateFastSyncingMetric()
conR.BaseReactor = *p2p.NewBaseReactor("ConsensusReactor", conR)


+ 7
- 14
consensus/state.go View File

@ -1642,21 +1642,14 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
precommits := cs.Votes.Precommits(vote.Round)
cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())
blockID, ok := precommits.TwoThirdsMajority()
if ok {
if len(blockID.Hash) == 0 {
cs.enterNewRound(height, vote.Round+1)
} else {
cs.enterNewRound(height, vote.Round)
cs.enterPrecommit(height, vote.Round)
cs.enterCommit(height, vote.Round)
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
// if we have all the votes now,
// go straight to new round (skip timeout commit)
// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, cstypes.RoundStepNewHeight)
cs.enterNewRound(cs.Height, 0)
}
if ok && len(blockID.Hash) != 0 {
// Executed as TwoThirdsMajority could be from a higher round
cs.enterNewRound(height, vote.Round)
cs.enterPrecommit(height, vote.Round)
cs.enterCommit(height, vote.Round)
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
cs.enterNewRound(cs.Height, 0)
}
} else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() {
cs.enterNewRound(height, vote.Round)


+ 127
- 110
consensus/state_test.go View File

@ -67,23 +67,23 @@ func TestStateProposerSelection0(t *testing.T) {
startTestRound(cs1, height, round)
// wait for new round so proposer is set
<-newRoundCh
// Wait for new round so proposer is set.
ensureNewRound(newRoundCh)
// lets commit a block and ensure proposer for the next height is correct
// Commit a block and ensure proposer for the next height is correct.
prop := cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) {
t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
}
// wait for complete proposal
<-proposalCh
// Wait for complete proposal.
ensureNewProposal(proposalCh)
rs := cs1.GetRoundState()
signAddVotes(cs1, types.VoteTypePrecommit, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
// wait for new round so next validator is set
<-newRoundCh
// Wait for new round so next validator is set.
ensureNewRound(newRoundCh)
prop = cs1.GetRoundState().Validators.GetProposer()
if !bytes.Equal(prop.Address, vss[1].GetAddress()) {
@ -102,7 +102,7 @@ func TestStateProposerSelection2(t *testing.T) {
incrementRound(vss[1:]...)
startTestRound(cs1, cs1.Height, 2)
<-newRoundCh // wait for the new round
ensureNewRound(newRoundCh) // wait for the new round
// everyone just votes nil. we get a new proposer each round
for i := 0; i < len(vss); i++ {
@ -114,8 +114,7 @@ func TestStateProposerSelection2(t *testing.T) {
rs := cs1.GetRoundState()
signAddVotes(cs1, types.VoteTypePrecommit, nil, rs.ProposalBlockParts.Header(), vss[1:]...)
<-newRoundCh // wait for the new round event each round
ensureNewRound(newRoundCh) // wait for the new round event each round
incrementRound(vss[1:]...)
}
@ -133,13 +132,7 @@ func TestStateEnterProposeNoPrivValidator(t *testing.T) {
startTestRound(cs, height, round)
// if we're not a validator, EnterPropose should timeout
ticker := time.NewTicker(ensureProposeTimeout(cs.config.TimeoutPropose))
select {
case <-timeoutCh:
case <-ticker.C:
panic("Expected EnterPropose to timeout")
}
ensureNewTimeout(timeoutCh, cs.config.TimeoutPropose.Nanoseconds())
if cs.GetRoundState().Proposal != nil {
t.Error("Expected to make no proposal, since no privValidator")
@ -159,7 +152,7 @@ func TestStateEnterProposeYesPrivValidator(t *testing.T) {
cs.enterNewRound(height, round)
cs.startRoutines(3)
<-proposalCh
ensureNewProposal(proposalCh)
// Check that Proposal, ProposalBlock, ProposalBlockParts are set.
rs := cs.GetRoundState()
@ -174,13 +167,7 @@ func TestStateEnterProposeYesPrivValidator(t *testing.T) {
}
// if we're a validator, enterPropose should not timeout
ticker := time.NewTicker(ensureProposeTimeout(cs.config.TimeoutPropose))
select {
case <-timeoutCh:
panic("Expected EnterPropose not to timeout")
case <-ticker.C:
}
ensureNoNewTimeout(timeoutCh, cs.config.TimeoutPropose.Nanoseconds())
}
func TestStateBadProposal(t *testing.T) {
@ -221,19 +208,19 @@ func TestStateBadProposal(t *testing.T) {
startTestRound(cs1, height, round)
// wait for proposal
<-proposalCh
ensureNewProposal(proposalCh)
// wait for prevote
<-voteCh
ensureNewVote(voteCh)
validatePrevote(t, cs1, round, vss[0], nil)
// add bad prevote from vs2 and wait for it
signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
ensureNewVote(voteCh)
// wait for precommit
<-voteCh
ensureNewVote(voteCh)
validatePrecommit(t, cs1, round, 0, vss[0], nil, nil)
signAddVotes(cs1, types.VoteTypePrecommit, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
@ -261,19 +248,19 @@ func TestStateFullRound1(t *testing.T) {
startTestRound(cs, height, round)
<-newRoundCh
ensureNewRound(newRoundCh)
// grab proposal
re := <-propCh
propBlockHash := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState).ProposalBlock.Hash()
<-voteCh // wait for prevote
ensureNewVote(voteCh) // wait for prevote
validatePrevote(t, cs, round, vss[0], propBlockHash)
<-voteCh // wait for precommit
ensureNewVote(voteCh) // wait for precommit
// we're going to roll right into new height
<-newRoundCh
ensureNewRound(newRoundCh)
validateLastPrecommit(t, cs, vss[0], propBlockHash)
}
@ -288,8 +275,8 @@ func TestStateFullRoundNil(t *testing.T) {
cs.enterPrevote(height, round)
cs.startRoutines(4)
<-voteCh // prevote
<-voteCh // precommit
ensureNewVote(voteCh) // prevote
ensureNewVote(voteCh) // precommit
// should prevote and precommit nil
validatePrevoteAndPrecommit(t, cs, round, 0, vss[0], nil, nil)
@ -308,7 +295,7 @@ func TestStateFullRound2(t *testing.T) {
// start round and wait for propose and prevote
startTestRound(cs1, height, round)
<-voteCh // prevote
ensureNewVote(voteCh) // prevote
// we should be stuck in limbo waiting for more prevotes
rs := cs1.GetRoundState()
@ -316,9 +303,9 @@ func TestStateFullRound2(t *testing.T) {
// prevote arrives from vs2:
signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propPartsHeader, vs2)
<-voteCh
ensureNewVote(voteCh)
<-voteCh //precommit
ensureNewVote(voteCh) //precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], propBlockHash, propBlockHash)
@ -327,10 +314,10 @@ func TestStateFullRound2(t *testing.T) {
// precommit arrives from vs2:
signAddVotes(cs1, types.VoteTypePrecommit, propBlockHash, propPartsHeader, vs2)
<-voteCh
ensureNewVote(voteCh)
// wait to finish commit, propose in next height
<-newBlockCh
ensureNewBlock(newBlockCh)
}
//------------------------------------------------------------------------------------------
@ -363,14 +350,14 @@ func TestStateLockNoPOL(t *testing.T) {
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
ensureNewVote(voteCh) // prevote
// we should now be stuck in limbo forever, waiting for more prevotes
// prevote arrives from vs2:
signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2)
<-voteCh // prevote
ensureNewVote(voteCh) // prevote
<-voteCh // precommit
ensureNewVote(voteCh) // precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
@ -382,15 +369,15 @@ func TestStateLockNoPOL(t *testing.T) {
copy(hash, theBlockHash)
hash[0] = byte((hash[0] + 1) % 255)
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh // precommit
ensureNewVote(voteCh) // precommit
// (note we're entering precommit for a second time this round)
// but with invalid args. then we enterPrecommitWait, and the timeout to new round
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
///
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("#### ONTO ROUND 1")
/*
Round2 (cs1, B) // B B2
@ -407,20 +394,20 @@ func TestStateLockNoPOL(t *testing.T) {
}
// wait to finish prevote
<-voteCh
ensureNewVote(voteCh)
// we should have prevoted our locked block
validatePrevote(t, cs1, 1, vss[0], rs.LockedBlock.Hash())
// add a conflicting prevote from the other validator
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
ensureNewVote(voteCh)
// now we're going to enter prevote again, but with invalid args
// and then prevote wait, which should timeout. then wait for precommit
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrevote.Nanoseconds())
<-voteCh // precommit
ensureNewVote(voteCh) // precommit
// the proposed block should still be locked and our precommit added
// we should precommit nil and be locked on the proposal
@ -429,13 +416,13 @@ func TestStateLockNoPOL(t *testing.T) {
// add conflicting precommit from vs2
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
ensureNewVote(voteCh)
// (note we're entering precommit for a second time this round, but with invalid args
// then we enterPrecommitWait and timeout into NewRound
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("#### ONTO ROUND 2")
/*
Round3 (vs2, _) // B, B2
@ -451,22 +438,22 @@ func TestStateLockNoPOL(t *testing.T) {
panic(fmt.Sprintf("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock))
}
<-voteCh // prevote
ensureNewVote(voteCh) // prevote
validatePrevote(t, cs1, 2, vss[0], rs.LockedBlock.Hash())
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
ensureNewVote(voteCh)
<-timeoutWaitCh // prevote wait
<-voteCh // precommit
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrevote.Nanoseconds())
ensureNewVote(voteCh) // precommit
validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2) // NOTE: conflicting precommits at same height
<-voteCh
ensureNewVote(voteCh)
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
// before we time out into new round, set next proposal block
prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
@ -476,7 +463,7 @@ func TestStateLockNoPOL(t *testing.T) {
incrementRound(vs2)
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("#### ONTO ROUND 3")
/*
Round4 (vs2, C) // B C // B C
@ -488,22 +475,22 @@ func TestStateLockNoPOL(t *testing.T) {
t.Fatal(err)
}
<-proposalCh
<-voteCh // prevote
ensureNewProposal(proposalCh)
ensureNewVote(voteCh) // prevote
// prevote for locked block (not proposal)
validatePrevote(t, cs1, 0, vss[0], cs1.LockedBlock.Hash())
signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2)
<-voteCh
ensureNewVote(voteCh)
<-timeoutWaitCh
<-voteCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrevote.Nanoseconds())
ensureNewVote(voteCh)
validatePrecommit(t, cs1, 2, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal
signAddVotes(cs1, types.VoteTypePrecommit, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) // NOTE: conflicting precommits at same height
<-voteCh
ensureNewVote(voteCh)
}
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
@ -531,18 +518,18 @@ func TestStateLockPOLRelock(t *testing.T) {
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
ensureNewRound(newRoundCh)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
ensureNewVote(voteCh) // prevote
signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2, vs3, vs4)
// prevotes
discardFromChan(voteCh, 3)
<-voteCh // our precommit
ensureNewVote(voteCh) // our precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
@ -560,14 +547,14 @@ func TestStateLockPOLRelock(t *testing.T) {
incrementRound(vs2, vs3, vs4)
// timeout to new round
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("### ONTO ROUND 1")
/*
@ -585,7 +572,7 @@ func TestStateLockPOLRelock(t *testing.T) {
}
// go to prevote, prevote for locked block (not proposal), move on
<-voteCh
ensureNewVote(voteCh)
validatePrevote(t, cs1, 0, vss[0], theBlockHash)
// now lets add prevotes from everyone else for the new block
@ -625,6 +612,8 @@ func TestStateLockPOLRelock(t *testing.T) {
func TestStateLockPOLUnlock(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
h := cs1.GetRoundState().Height
r := cs1.GetRoundState().Round
partSize := types.BlockPartSizeBytes
@ -644,20 +633,20 @@ func TestStateLockPOLUnlock(t *testing.T) {
*/
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
startTestRound(cs1, h, r)
ensureNewRound(newRoundCh)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
ensureVote(voteCh, h, r, types.VoteTypePrevote)
signAddVotes(cs1, types.VoteTypePrevote, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), vs2, vs3, vs4)
<-voteCh //precommit
ensureVote(voteCh, h, r, types.VoteTypePrecommit)
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
validatePrecommit(t, cs1, r, 0, vss[0], theBlockHash, theBlockHash)
rs = cs1.GetRoundState()
@ -681,7 +670,7 @@ func TestStateLockPOLUnlock(t *testing.T) {
t.Fatal(err)
}
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("#### ONTO ROUND 1")
/*
Round2 (vs2, C) // B nil nil nil // nil nil nil _
@ -698,21 +687,21 @@ func TestStateLockPOLUnlock(t *testing.T) {
}
// go to prevote, prevote for locked block (not proposal)
<-voteCh
ensureVote(voteCh, h, r+1, types.VoteTypePrevote)
validatePrevote(t, cs1, 0, vss[0], lockedBlockHash)
// now lets add prevotes from everyone else for nil (a polka!)
signAddVotes(cs1, types.VoteTypePrevote, nil, types.PartSetHeader{}, vs2, vs3, vs4)
// the polka makes us unlock and precommit nil
<-unlockCh
<-voteCh // precommit
ensureNewUnlock(unlockCh)
ensureVote(voteCh, h, r+1, types.VoteTypePrecommit)
// we should have unlocked and committed nil
// NOTE: since we don't relock on nil, the lock round is 0
validatePrecommit(t, cs1, 1, 0, vss[0], nil, nil)
validatePrecommit(t, cs1, r+1, 0, vss[0], nil, nil)
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3)
<-newRoundCh
ensureNewRound(newRoundCh)
}
// 4 vals
@ -722,6 +711,8 @@ func TestStateLockPOLUnlock(t *testing.T) {
func TestStateLockPOLSafety1(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
h := cs1.GetRoundState().Height
r := cs1.GetRoundState().Round
partSize := types.BlockPartSizeBytes
@ -733,12 +724,12 @@ func TestStateLockPOLSafety1(t *testing.T) {
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
ensureNewRound(newRoundCh)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
<-voteCh // prevote
ensureVote(voteCh, h, r, types.VoteTypePrevote)
validatePrevote(t, cs1, 0, vss[0], propBlock.Hash())
@ -747,6 +738,8 @@ func TestStateLockPOLSafety1(t *testing.T) {
// before we time out into new round, set next proposer
// and next proposal block
//TODO: Should we remove this?
/*
_, v1 := cs1.Validators.GetByAddress(vss[0].Address)
v1.VotingPower = 1
@ -759,6 +752,11 @@ func TestStateLockPOLSafety1(t *testing.T) {
// we do see them precommit nil
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensureVote(voteCh, h, r, types.VoteTypePrecommit)
ensureNewRound(newRoundCh)
t.Log("### ONTO ROUND 1")
prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
propBlockHash := propBlock.Hash()
propBlockParts := propBlock.MakePartSet(partSize)
@ -769,9 +767,6 @@ func TestStateLockPOLSafety1(t *testing.T) {
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
<-newRoundCh
t.Log("### ONTO ROUND 1")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
@ -792,24 +787,24 @@ func TestStateLockPOLSafety1(t *testing.T) {
}
t.Logf("new prop hash %v", fmt.Sprintf("%X", propBlockHash))
// go to prevote, prevote for proposal block
<-voteCh
ensureVote(voteCh, h, r+1, types.VoteTypePrevote)
validatePrevote(t, cs1, 1, vss[0], propBlockHash)
// now we see the others prevote for it, so we should lock on it
signAddVotes(cs1, types.VoteTypePrevote, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
<-voteCh // precommit
ensureVote(voteCh, h, r+1, types.VoteTypePrecommit)
// we should have precommitted
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3)
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
incrementRound(vs2, vs3, vs4)
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("### ONTO ROUND 2")
/*Round3
@ -817,10 +812,10 @@ func TestStateLockPOLSafety1(t *testing.T) {
*/
// timeout of propose
<-timeoutProposeCh
ensureNewTimeout(timeoutProposeCh, cs1.config.TimeoutPropose.Nanoseconds())
// finish prevote
<-voteCh
ensureVote(voteCh, h, r+2, types.VoteTypePrevote)
// we should prevote what we're locked on
validatePrevote(t, cs1, 2, vss[0], propBlockHash)
@ -845,6 +840,8 @@ func TestStateLockPOLSafety1(t *testing.T) {
func TestStateLockPOLSafety2(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
h := cs1.GetRoundState().Height
r := cs1.GetRoundState().Round
partSize := types.BlockPartSizeBytes
@ -876,20 +873,19 @@ func TestStateLockPOLSafety2(t *testing.T) {
t.Log("### ONTO Round 1")
// jump in at round 1
height := cs1.Height
startTestRound(cs1, height, 1)
<-newRoundCh
startTestRound(cs1, h, r+1)
ensureNewRound(newRoundCh)
if err := cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer"); err != nil {
t.Fatal(err)
}
<-proposalCh
ensureNewProposal(proposalCh)
<-voteCh // prevote
ensureVote(voteCh, h, r+1, types.VoteTypePrevote)
signAddVotes(cs1, types.VoteTypePrevote, propBlockHash1, propBlockParts1.Header(), vs2, vs3, vs4)
<-voteCh // precommit
ensureVote(voteCh, h, r+1, types.VoteTypePrecommit)
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash1, propBlockHash1)
@ -900,10 +896,10 @@ func TestStateLockPOLSafety2(t *testing.T) {
incrementRound(vs2, vs3, vs4)
// timeout of precommit wait to new round
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
// in round 2 we see the polkad block from round 0
newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0, propBlockID1)
newProp := types.NewProposal(h, 2, propBlockParts0.Header(), 0, propBlockID1)
if err := vs3.SignProposal(config.ChainID(), newProp); err != nil {
t.Fatal(err)
}
@ -914,7 +910,7 @@ func TestStateLockPOLSafety2(t *testing.T) {
// Add the pol votes
addVotes(cs1, prevotes...)
<-newRoundCh
ensureNewRound(newRoundCh)
t.Log("### ONTO Round 2")
/*Round2
// now we see the polka from round 1, but we shouldnt unlock
@ -936,6 +932,26 @@ func TestStateLockPOLSafety2(t *testing.T) {
}
// 4 vals, 3 Nil Precommits at P0
// What we want:
// P0 waits for timeoutPrecommit before starting next round
func TestWaitingTimeoutOnNilPolka(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
// start round
startTestRound(cs1, cs1.Height, 0)
ensureNewRound(newRoundCh)
signAddVotes(cs1, types.VoteTypePrecommit, nil, types.PartSetHeader{}, vs2, vs3, vs4)
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
ensureNewRound(newRoundCh)
}
//------------------------------------------------------------------------------------------
// SlashingSuite
// TODO: Slashing
@ -1024,7 +1040,8 @@ func TestStateSlashingPrecommits(t *testing.T) {
func TestStateHalt1(t *testing.T) {
cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
h := cs1.GetRoundState().Height
r := cs1.GetRoundState().Round
partSize := types.BlockPartSizeBytes
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
@ -1035,16 +1052,16 @@ func TestStateHalt1(t *testing.T) {
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
ensureNewRound(newRoundCh)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
propBlock := rs.ProposalBlock
propBlockParts := propBlock.MakePartSet(partSize)
<-voteCh // prevote
ensureVote(voteCh, h, r, types.VoteTypePrevote)
signAddVotes(cs1, types.VoteTypePrevote, propBlock.Hash(), propBlockParts.Header(), vs3, vs4)
<-voteCh // precommit
ensureVote(voteCh, h, r, types.VoteTypePrecommit)
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], propBlock.Hash(), propBlock.Hash())
@ -1058,7 +1075,7 @@ func TestStateHalt1(t *testing.T) {
incrementRound(vs2, vs3, vs4)
// timeout to new round
<-timeoutWaitCh
ensureNewTimeout(timeoutWaitCh, cs1.config.TimeoutPrecommit.Nanoseconds())
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
@ -1069,14 +1086,14 @@ func TestStateHalt1(t *testing.T) {
*/
// go to prevote, prevote for locked block
<-voteCh // prevote
ensureVote(voteCh, h, r+1, types.VoteTypePrevote)
validatePrevote(t, cs1, 0, vss[0], rs.LockedBlock.Hash())
// now we receive the precommit from the previous round
addVotes(cs1, precommit4)
// receiving that precommit should take us straight to commit
<-newBlockCh
ensureNewBlock(newBlockCh)
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)


+ 1
- 0
lite/dynamic_verifier_test.go View File

@ -4,6 +4,7 @@ import (
"fmt"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"


+ 1
- 1
p2p/conn/connection.go View File

@ -756,7 +756,7 @@ func (ch *Channel) recvPacketMsg(packet PacketMsg) ([]byte, error) {
func (ch *Channel) updateStats() {
// Exponential decay of stats.
// TODO: optimize.
atomic.StoreInt64(&ch.recentlySent, int64(float64(atomic.LoadInt64(&ch.recentlySent)) * 0.8))
atomic.StoreInt64(&ch.recentlySent, int64(float64(atomic.LoadInt64(&ch.recentlySent))*0.8))
}
//----------------------------------------


+ 1
- 1
p2p/peer.go View File

@ -102,7 +102,7 @@ type peer struct {
// User data
Data *cmn.CMap
metrics *Metrics
metrics *Metrics
metricsTicker *time.Ticker
}


+ 1
- 1
p2p/test_util.go View File

@ -28,7 +28,7 @@ func CreateRandomPeer(outbound bool) *peer {
ID: netAddr.ID,
ListenAddr: netAddr.DialString(),
},
mconn: &conn.MConnection{},
mconn: &conn.MConnection{},
metrics: NopMetrics(),
}
p.SetLogger(log.TestingLogger().With("peer", addr))


Loading…
Cancel
Save