Merge pull request #1560 from tendermint/jae/hotfix-update-validBlockRule

Suggested changes to consensus/reactor.go
This commit is contained in:
Ethan Buchman 2018-05-14 16:07:13 -04:00 committed by GitHub
commit 7bde50ca1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 42 deletions

View File

@ -696,31 +696,47 @@ func (conR *ConsensusReactor) gossipVotesForHeight(logger log.Logger, rs *cstype
return true return true
} }
} }
// If there are POL prevotes to send...
if prs.Step <= cstypes.RoundStepCommit && prs.Round != -1 && prs.Round <= rs.Round { if prs.Step <= cstypes.RoundStepPropose && prs.Round != -1 && prs.Round <= rs.Round && prs.ProposalPOLRound != -1 {
// If there are POLPrevotes to send... if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
if prs.ProposalPOLRound != -1 { if ps.PickSendVote(polPrevotes) {
if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil { logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
if ps.PickSendVote(polPrevotes) { "round", prs.ProposalPOLRound)
logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send", return true
"round", prs.ProposalPOLRound)
return true
}
} }
} }
}
// If there are prevotes to send... // If there are prevotes to send...
if prs.Step <= cstypes.RoundStepPrevoteWait && prs.Round != -1 && prs.Round <= rs.Round {
if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) { if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round) logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
return true return true
} }
}
// If there are precommits to send... // If there are precommits to send...
if prs.Step <= cstypes.RoundStepPrecommitWait && prs.Round != -1 && prs.Round <= rs.Round {
if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) { if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) {
logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round) logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round)
return true return true
} }
} }
// If there are prevotes to send...Needed because of validBlock mechanism
if prs.Round != -1 && prs.Round <= rs.Round {
if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
return true
}
}
// If there are POLPrevotes to send...
if prs.ProposalPOLRound != -1 {
if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
if ps.PickSendVote(polPrevotes) {
logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
"round", prs.ProposalPOLRound)
return true
}
}
}
return false return false
} }

View File

@ -992,7 +992,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
blockID, ok := cs.Votes.Prevotes(round).TwoThirdsMajority() blockID, ok := cs.Votes.Prevotes(round).TwoThirdsMajority()
// If we don't have a polka, we must precommit nil // If we don't have a polka, we must precommit nil.
if !ok { if !ok {
if cs.LockedBlock != nil { if cs.LockedBlock != nil {
cs.Logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit while we're locked. Precommitting nil") cs.Logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit while we're locked. Precommitting nil")
@ -1003,10 +1003,10 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
return return
} }
// At this point +2/3 prevoted for a particular block or nil // At this point +2/3 prevoted for a particular block or nil.
cs.eventBus.PublishEventPolka(cs.RoundStateEvent()) cs.eventBus.PublishEventPolka(cs.RoundStateEvent())
// the latest POLRound should be this round // the latest POLRound should be this round.
polRound, _ := cs.Votes.POLInfo() polRound, _ := cs.Votes.POLInfo()
if polRound < round { if polRound < round {
cmn.PanicSanity(cmn.Fmt("This POLRound should be %v but got %", round, polRound)) cmn.PanicSanity(cmn.Fmt("This POLRound should be %v but got %", round, polRound))
@ -1307,19 +1307,20 @@ func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, v
// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
// Update ValidBlock // Update Valid* if we can.
prevotes := cs.Votes.Prevotes(cs.Round) prevotes := cs.Votes.Prevotes(cs.Round)
blockID, ok := prevotes.TwoThirdsMajority() blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
if ok && !blockID.IsZero() && (cs.ValidRound < cs.Round) { if hasTwoThirds && !blockID.IsZero() && (cs.ValidRound < cs.Round) {
// update valid value
if cs.ProposalBlock.HashesTo(blockID.Hash) { if cs.ProposalBlock.HashesTo(blockID.Hash) {
cs.ValidRound = cs.Round cs.ValidRound = cs.Round
cs.ValidBlock = cs.ProposalBlock cs.ValidBlock = cs.ProposalBlock
cs.ValidBlockParts = cs.ProposalBlockParts cs.ValidBlockParts = cs.ProposalBlockParts
} }
//TODO: In case there is +2/3 majority in Prevotes set for some block and cs.ProposalBlock contains different block, // TODO: In case there is +2/3 majority in Prevotes set for some
//either proposer is faulty or voting power of faulty processes is more than 1/3. We should // block and cs.ProposalBlock contains different block, either
//trigger in the future accountability procedure at this point. // proposer is faulty or voting power of faulty processes is more
// than 1/3. We should trigger in the future accountability
// procedure at this point.
} }
if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() { if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() {
@ -1412,33 +1413,43 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
case types.VoteTypePrevote: case types.VoteTypePrevote:
prevotes := cs.Votes.Prevotes(vote.Round) prevotes := cs.Votes.Prevotes(vote.Round)
cs.Logger.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort()) cs.Logger.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())
blockID, ok := prevotes.TwoThirdsMajority()
// First, unlock if prevotes is a valid POL. // If +2/3 prevotes for a block or nil for *any* round:
// >> lockRound < POLRound <= unlockOrChangeLockRound (see spec) if blockID, ok := prevotes.TwoThirdsMajority(); ok {
// NOTE: If (lockRound < POLRound) but !(POLRound <= unlockOrChangeLockRound),
// we'll still enterNewRound(H,vote.R) and enterPrecommit(H,vote.R) to process it // First, unlock if prevotes is a valid POL.
// there. // `lockRound < POLRound <= unlockOrChangeLockRound (see spec)`
if (cs.LockedBlock != nil) && (cs.LockedRound < vote.Round) && (vote.Round <= cs.Round) { // NOTE: If `lockRound < POLRound` but `!(POLRound <=
if ok && !cs.LockedBlock.HashesTo(blockID.Hash) { // unlockOrChangeLockRound)`, we'll still enterNewRound(H,vote.R)
// and enterPrecommit(H,vote.R) to process it there.
if (cs.LockedBlock != nil) &&
(cs.LockedRound < vote.Round) &&
(vote.Round <= cs.Round) &&
!cs.LockedBlock.HashesTo(blockID.Hash) {
cs.Logger.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round) cs.Logger.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round)
cs.LockedRound = 0 cs.LockedRound = 0
cs.LockedBlock = nil cs.LockedBlock = nil
cs.LockedBlockParts = nil cs.LockedBlockParts = nil
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent()) cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
} }
}
// Update ValidBlock // Update Valid* if we can.
if ok && !blockID.IsZero() && (cs.ValidRound < vote.Round) && (vote.Round <= cs.Round) { if !blockID.IsZero() &&
// update valid value (cs.ValidRound < vote.Round) &&
if cs.ProposalBlock.HashesTo(blockID.Hash) { (vote.Round <= cs.Round) &&
cs.ProposalBlock.HashesTo(blockID.Hash) {
cs.ValidRound = vote.Round cs.ValidRound = vote.Round
cs.ValidBlock = cs.ProposalBlock cs.ValidBlock = cs.ProposalBlock
cs.ValidBlockParts = cs.ProposalBlockParts cs.ValidBlockParts = cs.ProposalBlockParts
// TODO: We might want to update ValidBlock also in case we
// don't have that block yet, and obtain the required block
// using gossiping
} }
//TODO: We might want to update ValidBlock also in case we don't have that block yet,
// and obtain the required block using gossiping
} }
// If +2/3 prevotes for *anything* for this or future round:
if cs.Round <= vote.Round && prevotes.HasTwoThirdsAny() { if cs.Round <= vote.Round && prevotes.HasTwoThirdsAny() {
// Round-skip over to PrevoteWait or goto Precommit. // Round-skip over to PrevoteWait or goto Precommit.
cs.enterNewRound(height, vote.Round) // if the vote is ahead of us cs.enterNewRound(height, vote.Round) // if the vote is ahead of us
@ -1454,6 +1465,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
cs.enterPrevote(height, cs.Round) cs.enterPrevote(height, cs.Round)
} }
} }
case types.VoteTypePrecommit: case types.VoteTypePrecommit:
precommits := cs.Votes.Precommits(vote.Round) precommits := cs.Votes.Precommits(vote.Round)
cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort()) cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())

View File

@ -67,9 +67,9 @@ type RoundState struct {
LockedRound int LockedRound int
LockedBlock *types.Block LockedBlock *types.Block
LockedBlockParts *types.PartSet LockedBlockParts *types.PartSet
ValidRound int ValidRound int // Last known round with POL for non-nil valid block.
ValidBlock *types.Block ValidBlock *types.Block // Last known block of POL mentioned above.
ValidBlockParts *types.PartSet ValidBlockParts *types.PartSet // Last known block parts of POL metnioned above.
Votes *HeightVoteSet Votes *HeightVoteSet
CommitRound int // CommitRound int //
LastCommit *types.VoteSet // Last precommits at Height-1 LastCommit *types.VoteSet // Last precommits at Height-1