本文整理汇总了Golang中github.com/tendermint/tendermint/types.EventStringTimeoutWait函数的典型用法代码示例。如果您正苦于以下问题:Golang EventStringTimeoutWait函数的具体用法?Golang EventStringTimeoutWait怎么用?Golang EventStringTimeoutWait使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了EventStringTimeoutWait函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: handleTimeout
func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs RoundState) {
log.Debug("Received tock", "timeout", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
// timeouts must be for current height, round, step
if ti.Height != rs.Height || ti.Round < rs.Round || (ti.Round == rs.Round && ti.Step < rs.Step) {
log.Debug("Ignoring tock because we're ahead", "height", rs.Height, "round", rs.Round, "step", rs.Step)
return
}
// the timeout will now cause a state transition
cs.mtx.Lock()
defer cs.mtx.Unlock()
switch ti.Step {
case RoundStepNewHeight:
// NewRound event fired from enterNewRound.
// XXX: should we fire timeout here?
cs.enterNewRound(ti.Height, 0)
case RoundStepPropose:
cs.evsw.FireEvent(types.EventStringTimeoutPropose(), cs.RoundStateEvent())
cs.enterPrevote(ti.Height, ti.Round)
case RoundStepPrevoteWait:
cs.evsw.FireEvent(types.EventStringTimeoutWait(), cs.RoundStateEvent())
cs.enterPrecommit(ti.Height, ti.Round)
case RoundStepPrecommitWait:
cs.evsw.FireEvent(types.EventStringTimeoutWait(), cs.RoundStateEvent())
cs.enterNewRound(ti.Height, ti.Round+1)
default:
panic(Fmt("Invalid timeout step: %v", ti.Step))
}
}
示例2: TestBadProposal
func TestBadProposal(t *testing.T) {
css, privVals := simpleConsensusState(2)
cs1, cs2 := css[0], css[1]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan struct{})
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- struct{}{}
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- struct{}{}
})
cs1.SetFireable(evsw)
// make the second validator the proposer
propBlock := changeProposer(t, cs1, cs2)
// make the block bad by tampering with statehash
stateHash := propBlock.StateHash
stateHash[0] = byte((stateHash[0] + 1) % 255)
propBlock.StateHash = stateHash
propBlockParts := propBlock.MakePartSet()
proposal := types.NewProposal(cs2.Height, cs2.Round, propBlockParts.Header(), cs2.Votes.POLRound())
if err := cs2.privValidator.SignProposal(cs2.state.ChainID, proposal); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
// start round
cs1.EnterNewRound(cs1.Height, 0, false)
// now we're on a new round and not the proposer
<-cs1.NewStepCh()
// so set the proposal block (and fix voting power)
cs1.mtx.Lock()
cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = proposal, propBlock, propBlockParts
fixVotingPower(t, cs1, privVals[1].Address)
cs1.mtx.Unlock()
// and wait for timeout
<-timeoutChan
// go to prevote, prevote for nil (proposal is bad)
<-cs1.NewStepCh()
validatePrevote(t, cs1, 0, privVals[0], nil)
// add bad prevote from cs2. we should precommit nil
signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header())
_, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
validatePrecommit(t, cs1, 0, 0, privVals[0], nil, nil)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, propBlock.Hash(), propBlock.MakePartSet().Header())
}
示例3: EnterNewRound
// Enter: +2/3 precommits for nil at (height,round-1)
// Enter: `timeoutPrecommits` after any +2/3 precommits from (height,round-1)
// Enter: `startTime = commitTime+timeoutCommit` from NewHeight(height)
// NOTE: cs.StartTime was already set for height.
func (cs *ConsensusState) EnterNewRound(height int, round int, timedOut bool) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != RoundStepNewHeight) {
log.Debug(Fmt("EnterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
if timedOut {
cs.evsw.FireEvent(types.EventStringTimeoutWait(), cs.RoundStateEvent())
}
if now := time.Now(); cs.StartTime.After(now) {
log.Warn("Need to set a buffer and log.Warn() here for sanity.", "startTime", cs.StartTime, "now", now)
}
log.Notice(Fmt("EnterNewRound(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
// Increment validators if necessary
validators := cs.Validators
if cs.Round < round {
validators = validators.Copy()
validators.IncrementAccum(round - cs.Round)
}
// Setup new round
cs.Round = round
cs.Step = RoundStepNewRound
cs.Validators = validators
if round == 0 {
// We've already reset these upon new height,
// and meanwhile we might have received a proposal
// for round 0.
} else {
cs.Proposal = nil
cs.ProposalBlock = nil
cs.ProposalBlockParts = nil
}
cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
cs.evsw.FireEvent(types.EventStringNewRound(), cs.RoundStateEvent())
// Immediately go to EnterPropose.
go cs.EnterPropose(height, round)
}
示例4: TestHalt1
// 4 vals.
// we receive a final precommit after going into next round, but others might have gone to commit already!
func TestHalt1(t *testing.T) {
cs1, vss := randConsensusState(4)
cs2, cs3, cs4 := vss[1], vss[2], vss[3]
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
propBlock := rs.ProposalBlock
propBlockParts := propBlock.MakePartSet()
<-voteCh // prevote
signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlock.Hash(), propBlockParts.Header(), cs3, cs4)
<-voteCh // precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], propBlock.Hash(), propBlock.Hash())
// add precommits from the rest
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, nil, types.PartSetHeader{}) // didnt receive proposal
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, propBlock.Hash(), propBlockParts.Header())
// we receive this later, but cs3 might receive it earlier and with ours will go to commit!
precommit4 := signVote(cs4, types.VoteTypePrecommit, propBlock.Hash(), propBlockParts.Header())
incrementRound(cs2, cs3, cs4)
// timeout to new round
<-timeoutWaitCh
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
log.Notice("### ONTO ROUND 1")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
*/
// go to prevote, prevote for locked block
<-voteCh // prevote
validatePrevote(t, cs1, 0, vss[0], rs.LockedBlock.Hash())
// now we receive the precommit from the previous round
addVoteToFrom(cs1, cs4, precommit4)
// receiving that precommit should take us straight to commit
<-newBlockCh
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
if rs.Height != 2 {
t.Fatal("expected height to increment")
}
}
示例5: TestLockPOLSafety2
// What we want:
// dont see P0, lock on P1 at R1, dont unlock using P0 at R2
func TestLockPOLSafety2(t *testing.T) {
cs1, vss := randConsensusState(4)
cs2, cs3, cs4 := vss[1], vss[2], vss[3]
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
// the block for R0: gets polkad but we miss it
// (even though we signed it, shhh)
_, propBlock0 := decideProposal(cs1, vss[0], cs1.Height, cs1.Round)
propBlockHash0 := propBlock0.Hash()
propBlockParts0 := propBlock0.MakePartSet()
// the others sign a polka but we don't see it
prevotes := signVoteMany(types.VoteTypePrevote, propBlockHash0, propBlockParts0.Header(), cs2, cs3, cs4)
// the block for round 1
prop1, propBlock1 := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
propBlockHash1 := propBlock1.Hash()
propBlockParts1 := propBlock1.MakePartSet()
incrementRound(cs2, cs3, cs4)
cs1.updateRoundStep(0, RoundStepPrecommitWait)
log.Notice("### ONTO Round 1")
// jump in at round 1
height := cs1.Height
startTestRound(cs1, height, 1)
<-newRoundCh
cs1.SetProposalAndBlock(prop1, propBlock1, propBlockParts1, "some peer")
<-proposalCh
<-voteCh // prevote
signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash1, propBlockParts1.Header(), cs2, cs3, cs4)
<-voteCh // precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash1, propBlockHash1)
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, propBlockHash1, propBlockParts1.Header())
incrementRound(cs2, cs3, cs4)
// timeout of precommit wait to new round
<-timeoutWaitCh
// in round 2 we see the polkad block from round 0
newProp := types.NewProposal(height, 2, propBlockParts0.Header(), 0)
if err := cs3.SignProposal(chainID, newProp); err != nil {
t.Fatal(err)
}
cs1.SetProposalAndBlock(newProp, propBlock0, propBlockParts0, "some peer")
addVoteToFromMany(cs1, prevotes, cs2, cs3, cs4) // add the pol votes
<-newRoundCh
log.Notice("### ONTO Round 2")
/*Round2
// now we see the polka from round 1, but we shouldnt unlock
*/
select {
case <-timeoutProposeCh:
<-proposalCh
case <-proposalCh:
}
select {
case <-unlockCh:
t.Fatal("validator unlocked using an old polka")
case <-voteCh:
// prevote our locked block
}
validatePrevote(t, cs1, 2, vss[0], propBlockHash1)
}
示例6: TestLockPOLSafety1
// 4 vals
// a polka at round 1 but we miss it
// then a polka at round 2 that we lock on
// then we see the polka from round 1 but shouldn't unlock
func TestLockPOLSafety1(t *testing.T) {
cs1, vss := randConsensusState(4)
cs2, cs3, cs4 := vss[1], vss[2], vss[3]
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
propBlock := rs.ProposalBlock
<-voteCh // prevote
validatePrevote(t, cs1, 0, vss[0], propBlock.Hash())
// the others sign a polka but we don't see it
prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
// before we time out into new round, set next proposer
// and next proposal block
/*
_, v1 := cs1.Validators.GetByAddress(vss[0].Address)
v1.VotingPower = 1
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}*/
log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
// we do see them precommit nil
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
propBlockHash := propBlock.Hash()
propBlockParts := propBlock.MakePartSet()
incrementRound(cs2, cs3, cs4)
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
<-newRoundCh
log.Notice("### ONTO ROUND 1")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
*/
// now we're on a new round and not the proposer,
// but we should receive the proposal
select {
case re = <-proposalCh:
case <-timeoutProposeCh:
re = <-proposalCh
}
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
if rs.LockedBlock != nil {
t.Fatal("we should not be locked!")
}
log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
// go to prevote, prevote for proposal block
<-voteCh
validatePrevote(t, cs1, 1, vss[0], propBlockHash)
// now we see the others prevote for it, so we should lock on it
signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3, cs4)
<-voteCh // precommit
// we should have precommitted
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3)
<-timeoutWaitCh
incrementRound(cs2, cs3, cs4)
<-newRoundCh
log.Notice("### ONTO ROUND 2")
/*Round3
we see the polka from round 1 but we shouldn't unlock!
*/
// timeout of propose
<-timeoutProposeCh
//.........这里部分代码省略.........
示例7: TestLockPOLUnlock
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLUnlock(t *testing.T) {
cs1, vss := randConsensusState(4)
cs2, cs3, cs4 := vss[1], vss[2], vss[3]
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
unlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringUnlock(), 1)
voteCh := subscribeToVoter(cs1, cs1.privValidator.Address)
// everything done from perspective of cs1
/*
Round1 (cs1, B) // B B B B // B nil B nil
eg. didn't see the 2/3 prevotes
*/
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
<-voteCh //precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
// before we time out into new round, set next proposal block
prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
propBlockParts := propBlock.MakePartSet()
incrementRound(cs2, cs3, cs4)
// timeout to new round
re = <-timeoutWaitCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
lockedBlockHash := rs.LockedBlock.Hash()
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
<-newRoundCh
log.Notice("#### ONTO ROUND 1")
/*
Round2 (cs2, C) // B nil nil nil // nil nil nil _
cs1 unlocks!
*/
// now we're on a new round and not the proposer,
// but we should receive the proposal
select {
case <-proposalCh:
case <-timeoutProposeCh:
<-proposalCh
}
// go to prevote, prevote for locked block (not proposal)
<-voteCh
validatePrevote(t, cs1, 0, vss[0], lockedBlockHash)
// now lets add prevotes from everyone else for nil (a polka!)
signAddVoteToFromMany(types.VoteTypePrevote, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
// the polka makes us unlock and precommit nil
<-unlockCh
<-voteCh // precommit
// 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)
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3)
<-newRoundCh
}
示例8: TestLockPOLRelock
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLRelock(t *testing.T) {
cs1, vss := randConsensusState(4)
cs2, cs3, cs4 := vss[1], vss[2], vss[3]
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
newBlockCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewBlock(), 1)
log.Debug("cs2 last round", "lr", cs2.PrivValidator.LastRound)
// everything done from perspective of cs1
/*
Round1 (cs1, B) // B B B B// B nil B nil
eg. cs2 and cs4 didn't see the 2/3 prevotes
*/
// start round and wait for propose and prevote
startTestRound(cs1, cs1.Height, 0)
<-newRoundCh
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
_, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
<-voteCh // our precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
_, _, _ = <-voteCh, <-voteCh, <-voteCh // precommits
// before we timeout to the new round set the new proposal
prop, propBlock := decideProposal(cs1, cs2, cs2.Height, cs2.Round+1)
propBlockParts := propBlock.MakePartSet()
propBlockHash := propBlock.Hash()
incrementRound(cs2, cs3, cs4)
// timeout to new round
<-timeoutWaitCh
//XXX: this isnt gauranteed to get there before the timeoutPropose ...
cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer")
<-newRoundCh
log.Notice("### ONTO ROUND 1")
/*
Round2 (cs2, C) // B C C C // C C C _)
cs1 changes lock!
*/
// now we're on a new round and not the proposer
// but we should receive the proposal
select {
case <-proposalCh:
case <-timeoutProposeCh:
<-proposalCh
}
// go to prevote, prevote for locked block (not proposal), move on
<-voteCh
validatePrevote(t, cs1, 0, vss[0], theBlockHash)
// now lets add prevotes from everyone else for the new block
signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3, cs4)
_, _, _ = <-voteCh, <-voteCh, <-voteCh // prevotes
// now either we go to PrevoteWait or Precommit
select {
case <-timeoutWaitCh: // we're in PrevoteWait, go to Precommit
<-voteCh
case <-voteCh: // we went straight to Precommit
}
// we should have unlocked and locked on the new block
validatePrecommit(t, cs1, 1, 1, vss[0], propBlockHash, propBlockHash)
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3)
_, _ = <-voteCh, <-voteCh
be := <-newBlockCh
b := be.(types.EventDataNewBlock)
re = <-newRoundCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
if rs.Height != 2 {
//.........这里部分代码省略.........
示例9: TestLockNoPOL
// two validators, 4 rounds.
// two vals take turns proposing. val1 locks on first one, precommits nil on everything else
func TestLockNoPOL(t *testing.T) {
cs1, vss := randConsensusState(2)
cs2 := vss[1]
height := cs1.Height
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
newRoundCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringNewRound(), 1)
/*
Round1 (cs1, B) // B B // B B2
*/
// start round and wait for prevote
cs1.enterNewRound(height, 0)
cs1.startRoutines(0)
re := <-proposalCh
rs := re.(types.EventDataRoundState).RoundState.(*RoundState)
theBlockHash := rs.ProposalBlock.Hash()
<-voteCh // prevote
// we should now be stuck in limbo forever, waiting for more prevotes
// prevote arrives from cs2:
signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
<-voteCh // prevote
<-voteCh // precommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, vss[0], theBlockHash, theBlockHash)
// we should now be stuck in limbo forever, waiting for more precommits
// lets add one for a different block
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
hash := make([]byte, len(theBlockHash))
copy(hash, theBlockHash)
hash[0] = byte((hash[0] + 1) % 255)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header())
<-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
///
<-newRoundCh
log.Notice("#### ONTO ROUND 1")
/*
Round2 (cs1, B) // B B2
*/
incrementRound(cs2)
// now we're on a new round and not the proposer, so wait for timeout
re = <-timeoutProposeCh
rs = re.(types.EventDataRoundState).RoundState.(*RoundState)
if rs.ProposalBlock != nil {
t.Fatal("Expected proposal block to be nil")
}
// wait to finish prevote
<-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
signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header())
<-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
<-voteCh // precommit
// the proposed block should still be locked and our precommit added
// we should precommit nil and be locked on the proposal
validatePrecommit(t, cs1, 1, 0, vss[0], nil, theBlockHash)
// add conflicting precommit from cs2
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, rs.ProposalBlock.MakePartSet().Header())
<-voteCh
// (note we're entering precommit for a second time this round, but with invalid args
// then we enterPrecommitWait and timeout into NewRound
<-timeoutWaitCh
<-newRoundCh
log.Notice("#### ONTO ROUND 2")
/*
//.........这里部分代码省略.........
示例10: EnterPrecommit
// Enter: +2/3 precomits for block or nil.
// Enter: `timeoutPrevote` after any +2/3 prevotes.
// Enter: any +2/3 precommits for next round.
// Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this round)
// else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
// else, precommit nil otherwise.
func (cs *ConsensusState) EnterPrecommit(height int, round int, timedOut bool) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommit <= cs.Step) {
log.Debug(Fmt("EnterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
if timedOut {
cs.evsw.FireEvent(types.EventStringTimeoutWait(), cs.RoundStateEvent())
}
log.Info(Fmt("EnterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
defer func() {
// Done EnterPrecommit:
cs.Round = round
cs.Step = RoundStepPrecommit
cs.newStepCh <- cs.getRoundState()
}()
hash, partsHeader, ok := cs.Votes.Prevotes(round).TwoThirdsMajority()
// If we don't have a polka, we must precommit nil
if !ok {
if cs.LockedBlock != nil {
log.Info("EnterPrecommit: No +2/3 prevotes during EnterPrecommit while we're locked. Precommitting nil")
} else {
log.Info("EnterPrecommit: No +2/3 prevotes during EnterPrecommit. Precommitting nil.")
}
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
return
}
// At this point +2/3 prevoted for a particular block or nil
cs.evsw.FireEvent(types.EventStringPolka(), cs.RoundStateEvent())
// the latest POLRound should be this round
if cs.Votes.POLRound() < round {
PanicSanity(Fmt("This POLRound should be %v but got %", round, cs.Votes.POLRound()))
}
// +2/3 prevoted nil. Unlock and precommit nil.
if len(hash) == 0 {
if cs.LockedBlock == nil {
log.Info("EnterPrecommit: +2/3 prevoted for nil.")
} else {
log.Info("EnterPrecommit: +2/3 prevoted for nil. Unlocking")
cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil
cs.evsw.FireEvent(types.EventStringUnlock(), cs.RoundStateEvent())
}
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
return
}
// At this point, +2/3 prevoted for a particular block.
// If we're already locked on that block, precommit it, and update the LockedRound
if cs.LockedBlock.HashesTo(hash) {
log.Info("EnterPrecommit: +2/3 prevoted locked block. Relocking")
cs.LockedRound = round
cs.evsw.FireEvent(types.EventStringRelock(), cs.RoundStateEvent())
cs.signAddVote(types.VoteTypePrecommit, hash, partsHeader)
return
}
// If +2/3 prevoted for proposal block, stage and precommit it
if cs.ProposalBlock.HashesTo(hash) {
log.Info("EnterPrecommit: +2/3 prevoted proposal block. Locking", "hash", hash)
// Validate the block.
if err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts); err != nil {
PanicConsensus(Fmt("EnterPrecommit: +2/3 prevoted for an invalid block: %v", err))
}
cs.LockedRound = round
cs.LockedBlock = cs.ProposalBlock
cs.LockedBlockParts = cs.ProposalBlockParts
cs.evsw.FireEvent(types.EventStringLock(), cs.RoundStateEvent())
cs.signAddVote(types.VoteTypePrecommit, hash, partsHeader)
return
}
// There was a polka in this round for a block we don't have.
// Fetch that block, unlock, and precommit nil.
// The +2/3 prevotes for this round is the POL for our unlock.
// TODO: In the future save the POL prevotes for justification.
cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil
if !cs.ProposalBlockParts.HasHeader(partsHeader) {
cs.ProposalBlock = nil
cs.ProposalBlockParts = types.NewPartSetFromHeader(partsHeader)
}
//.........这里部分代码省略.........
示例11: TestLockPOLSafety2
// 4 vals.
// polka P1 at R1, P2 at R2, and P3 at R3,
// we lock on P1 at R1, don't see P2, and unlock using P3 at R3
// then we should make sure we don't lock using P2
func TestLockPOLSafety2(t *testing.T) {
css, privVals := simpleConsensusState(4)
cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan *types.EventDataRoundState)
voteChan := make(chan *types.EventDataVote)
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
vote := data.(*types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(cs1.privValidator.Address, vote.Address) {
voteChan <- vote
}
})
cs1.SetFireable(evsw)
// start round and wait for propose and prevote
cs1.EnterNewRound(cs1.Height, 0, false)
_, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
theBlockHash := cs1.ProposalBlock.Hash()
donePrecommit := make(chan struct{})
go func() {
<-voteChan
<-cs1.NewStepCh()
donePrecommit <- struct{}{}
}()
signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
<-donePrecommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
donePrecommitWait := make(chan struct{})
go func() {
<-cs1.NewStepCh()
donePrecommitWait <- struct{}{}
}()
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
<-donePrecommitWait
// before we time out into new round, set next proposer
// and next proposal block
_, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
v1.VotingPower = 1
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
cs2.decideProposal(cs2.Height, cs2.Round+1)
prop, propBlock := cs2.Proposal, cs2.ProposalBlock
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with cs2")
}
incrementRound(cs2, cs3, cs4)
// timeout to new round
<-timeoutChan
log.Info("### ONTO Round 2")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
*/
// now we're on a new round and not the proposer, so wait for timeout
_, _ = <-cs1.NewStepCh(), <-timeoutChan
// go to prevote, prevote for locked block
_, _ = <-voteChan, <-cs1.NewStepCh()
validatePrevote(t, cs1, 0, privVals[0], cs1.LockedBlock.Hash())
// the others sign a polka but we don't see it
prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
// once we see prevotes for the next round we'll skip ahead
incrementRound(cs2, cs3, cs4)
log.Info("### ONTO Round 3")
/*Round3
a polka for nil causes us to unlock
*/
// these prevotes will send us straight to precommit at the higher round
//.........这里部分代码省略.........
示例12: TestLockPOLSafety1
// 4 vals
// a polka at round 1 but we miss it
// then a polka at round 2 that we lock on
// then we see the polka from round 1 but shouldn't unlock
func TestLockPOLSafety1(t *testing.T) {
css, privVals := simpleConsensusState(4)
cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan *types.EventDataRoundState)
voteChan := make(chan *types.EventDataVote)
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
vote := data.(*types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(cs1.privValidator.Address, vote.Address) {
voteChan <- vote
}
})
cs1.SetFireable(evsw)
// start round and wait for propose and prevote
cs1.EnterNewRound(cs1.Height, 0, false)
_, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
propBlock := cs1.ProposalBlock
validatePrevote(t, cs1, 0, privVals[0], cs1.ProposalBlock.Hash())
// the others sign a polka but we don't see it
prevotes := signVoteMany(types.VoteTypePrevote, propBlock.Hash(), propBlock.MakePartSet().Header(), cs2, cs3, cs4)
// before we time out into new round, set next proposer
// and next proposal block
_, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
v1.VotingPower = 1
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
log.Warn("old prop", "hash", fmt.Sprintf("%X", propBlock.Hash()))
// we do see them precommit nil
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs3, cs4)
cs2.decideProposal(cs2.Height, cs2.Round+1)
prop, propBlock := cs2.Proposal, cs2.ProposalBlock
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with cs2")
}
incrementRound(cs2, cs3, cs4)
log.Info("### ONTO ROUND 2")
/*Round2
// we timeout and prevote our lock
// a polka happened but we didn't see it!
*/
// now we're on a new round and not the proposer,
<-cs1.NewStepCh()
// so set proposal
cs1.mtx.Lock()
propBlockHash, propBlockParts := propBlock.Hash(), propBlock.MakePartSet()
cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlockParts
cs1.mtx.Unlock()
// and wait for timeout
<-timeoutChan
if cs1.LockedBlock != nil {
t.Fatal("we should not be locked!")
}
log.Warn("new prop", "hash", fmt.Sprintf("%X", propBlockHash))
// go to prevote, prevote for proposal block
_, _ = <-voteChan, <-cs1.NewStepCh()
validatePrevote(t, cs1, 1, privVals[0], propBlockHash)
// now we see the others prevote for it, so we should lock on it
donePrecommit := make(chan struct{})
go func() {
select {
case <-cs1.NewStepCh(): // we're in PrevoteWait, go to Precommit
<-voteChan
case <-voteChan: // we went straight to Precommit
}
<-cs1.NewStepCh()
donePrecommit <- struct{}{}
}()
// now lets add prevotes from everyone else for nil
signAddVoteToFromMany(types.VoteTypePrevote, cs1, propBlockHash, propBlockParts.Header(), cs2, cs3, cs4)
<-donePrecommit
// we should have precommitted
validatePrecommit(t, cs1, 1, 1, privVals[0], propBlockHash, propBlockHash)
//.........这里部分代码省略.........
示例13: TestLockPOLUnlock
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLUnlock(t *testing.T) {
css, privVals := simpleConsensusState(4)
cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan *types.EventDataRoundState)
voteChan := make(chan *types.EventDataVote)
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
vote := data.(*types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(cs1.privValidator.Address, vote.Address) {
voteChan <- vote
}
})
cs1.SetFireable(evsw)
// everything done from perspective of cs1
/*
Round1 (cs1, B) // B B B B // B nil B nil
eg. didn't see the 2/3 prevotes
*/
// start round and wait for propose and prevote
cs1.EnterNewRound(cs1.Height, 0, false)
_, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
theBlockHash := cs1.ProposalBlock.Hash()
donePrecommit := make(chan struct{})
go func() {
<-voteChan
<-cs1.NewStepCh()
donePrecommit <- struct{}{}
}()
signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
<-donePrecommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
donePrecommitWait := make(chan struct{})
go func() {
<-cs1.NewStepCh()
donePrecommitWait <- struct{}{}
}()
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
<-donePrecommitWait
// before we time out into new round, set next proposer
// and next proposal block
_, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
v1.VotingPower = 1
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
cs2.decideProposal(cs2.Height, cs2.Round+1)
prop, propBlock := cs2.Proposal, cs2.ProposalBlock
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with cs2")
}
incrementRound(cs2, cs3, cs4)
// timeout to new round
<-timeoutChan
log.Info("#### ONTO ROUND 2")
/*
Round2 (cs2, C) // B nil nil nil // nil nil nil _
cs1 unlocks!
*/
// now we're on a new round and not the proposer,
<-cs1.NewStepCh()
cs1.mtx.Lock()
// so set the proposal block
cs1.Proposal, cs1.ProposalBlock, cs1.ProposalBlockParts = prop, propBlock, propBlock.MakePartSet()
lockedBlockHash := cs1.LockedBlock.Hash()
cs1.mtx.Unlock()
// and wait for timeout
<-timeoutChan
// go to prevote, prevote for locked block (not proposal)
_, _ = <-voteChan, <-cs1.NewStepCh()
validatePrevote(t, cs1, 0, privVals[0], lockedBlockHash)
//.........这里部分代码省略.........
示例14: TestLockPOLRelock
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestLockPOLRelock(t *testing.T) {
css, privVals := simpleConsensusState(4)
cs1, cs2, cs3, cs4 := css[0], css[1], css[2], css[3]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan *types.EventDataRoundState)
voteChan := make(chan *types.EventDataVote)
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- data.(*types.EventDataRoundState)
})
evsw.AddListenerForEvent("tester", types.EventStringVote(), func(data types.EventData) {
vote := data.(*types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(cs1.privValidator.Address, vote.Address) {
voteChan <- vote
}
})
cs1.SetFireable(evsw)
// everything done from perspective of cs1
/*
Round1 (cs1, B) // B B B B// B nil B nil
eg. cs2 and cs4 didn't see the 2/3 prevotes
*/
// start round and wait for propose and prevote
cs1.EnterNewRound(cs1.Height, 0, false)
_, _, _ = <-cs1.NewStepCh(), <-voteChan, <-cs1.NewStepCh()
theBlockHash := cs1.ProposalBlock.Hash()
// wait to finish precommit after prevotes done
// we do this in a go routine with another channel since otherwise
// we may get deadlock with EnterPrecommit waiting to send on newStepCh and the final
// signAddVoteToFrom waiting for the cs.mtx.Lock
donePrecommit := make(chan struct{})
go func() {
<-voteChan
<-cs1.NewStepCh()
donePrecommit <- struct{}{}
}()
signAddVoteToFromMany(types.VoteTypePrevote, cs1, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header(), cs2, cs3, cs4)
<-donePrecommit
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
donePrecommitWait := make(chan struct{})
go func() {
// (note we're entering precommit for a second time this round)
// but with invalid args. then we EnterPrecommitWait, twice (?)
<-cs1.NewStepCh()
donePrecommitWait <- struct{}{}
}()
// add precommits from the rest
signAddVoteToFromMany(types.VoteTypePrecommit, cs1, nil, types.PartSetHeader{}, cs2, cs4)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs3, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
<-donePrecommitWait
// before we time out into new round, set next proposer
// and next proposal block
_, v1 := cs1.Validators.GetByAddress(privVals[0].Address)
v1.VotingPower = 1
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
cs2.decideProposal(cs2.Height, cs2.Round+1)
prop, propBlock := cs2.Proposal, cs2.ProposalBlock
if prop == nil || propBlock == nil {
t.Fatal("Failed to create proposal block with cs2")
}
incrementRound(cs2, cs3, cs4)
// timeout to new round
te := <-timeoutChan
if te.Step != RoundStepPrecommitWait.String() {
t.Fatalf("expected to timeout of precommit into new round. got %v", te.Step)
}
log.Info("### ONTO ROUND 2")
/*
Round2 (cs2, C) // B C C C // C C C _)
cs1 changes lock!
*/
// now we're on a new round and not the proposer
<-cs1.NewStepCh()
cs1.mtx.Lock()
//.........这里部分代码省略.........
示例15: TestLockNoPOL
// two validators, 4 rounds.
// val1 proposes the first 2 rounds, and is locked in the first.
// val2 proposes the next two. val1 should precommit nil on all (except first where he locks)
func TestLockNoPOL(t *testing.T) {
css, privVals := simpleConsensusState(2)
cs1, cs2 := css[0], css[1]
cs1.newStepCh = make(chan *RoundState) // so it blocks
timeoutChan := make(chan struct{})
evsw := events.NewEventSwitch()
evsw.OnStart()
evsw.AddListenerForEvent("tester", types.EventStringTimeoutPropose(), func(data types.EventData) {
timeoutChan <- struct{}{}
})
evsw.AddListenerForEvent("tester", types.EventStringTimeoutWait(), func(data types.EventData) {
timeoutChan <- struct{}{}
})
cs1.SetFireable(evsw)
/*
Round1 (cs1, B) // B B // B B2
*/
// start round and wait for propose and prevote
cs1.EnterNewRound(cs1.Height, 0, false)
_, _ = <-cs1.NewStepCh(), <-cs1.NewStepCh()
// we should now be stuck in limbo forever, waiting for more prevotes
// prevote arrives from cs2:
signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, cs1.ProposalBlock.Hash(), cs1.ProposalBlockParts.Header())
cs1.mtx.Lock() // XXX: sigh
theBlockHash := cs1.ProposalBlock.Hash()
cs1.mtx.Unlock()
// wait to finish precommit
<-cs1.NewStepCh()
// the proposed block should now be locked and our precommit added
validatePrecommit(t, cs1, 0, 0, privVals[0], theBlockHash, theBlockHash)
// we should now be stuck in limbo forever, waiting for more precommits
// lets add one for a different block
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
hash := cs1.ProposalBlock.Hash()
hash[0] = byte((hash[0] + 1) % 255)
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
// (note we're entering precommit for a second time this round)
// but with invalid args. then we EnterPrecommitWait, and the timeout to new round
_, _ = <-cs1.NewStepCh(), <-timeoutChan
log.Info("#### ONTO ROUND 2")
/*
Round2 (cs1, B) // B B2
*/
incrementRound(cs2)
// go to prevote
<-cs1.NewStepCh()
// now we're on a new round and the proposer
if cs1.ProposalBlock != cs1.LockedBlock {
t.Fatalf("Expected proposal block to be locked block. Got %v, Expected %v", cs1.ProposalBlock, cs1.LockedBlock)
}
// wait to finish prevote
<-cs1.NewStepCh()
// we should have prevoted our locked block
validatePrevote(t, cs1, 1, privVals[0], cs1.LockedBlock.Hash())
// add a conflicting prevote from the other validator
signAddVoteToFrom(types.VoteTypePrevote, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
// now we're going to enter prevote again, but with invalid args
// and then prevote wait, which should timeout. then wait for precommit
_, _, _ = <-cs1.NewStepCh(), <-timeoutChan, <-cs1.NewStepCh()
// the proposed block should still be locked and our precommit added
// we should precommit nil and be locked on the proposal
validatePrecommit(t, cs1, 1, 0, privVals[0], nil, theBlockHash)
// add conflicting precommit from cs2
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
signAddVoteToFrom(types.VoteTypePrecommit, cs1, cs2, hash, cs1.ProposalBlockParts.Header())
// (note we're entering precommit for a second time this round, but with invalid args
// then we EnterPrecommitWait and timeout into NewRound
_, _ = <-cs1.NewStepCh(), <-timeoutChan
log.Info("#### ONTO ROUND 3")
/*
Round3 (cs2, _) // B, B2
*/
incrementRound(cs2)
// now we're on a new round and not the proposer, so wait for timeout
//.........这里部分代码省略.........