Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update consensus 2/3 to 1/2 #5

Open
wants to merge 3 commits into
base: findora-v0.33.9
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,21 +812,21 @@ func (cfg *ConsensusConfig) Propose(round int) time.Duration {
) * time.Nanosecond
}

// Prevote returns the amount of time to wait for straggler votes after receiving any +2/3 prevotes
// Prevote returns the amount of time to wait for straggler votes after receiving any +1/2 prevotes
func (cfg *ConsensusConfig) Prevote(round int) time.Duration {
return time.Duration(
cfg.TimeoutPrevote.Nanoseconds()+cfg.TimeoutPrevoteDelta.Nanoseconds()*int64(round),
) * time.Nanosecond
}

// Precommit returns the amount of time to wait for straggler votes after receiving any +2/3 precommits
// Precommit returns the amount of time to wait for straggler votes after receiving any +1/2 precommits
func (cfg *ConsensusConfig) Precommit(round int) time.Duration {
return time.Duration(
cfg.TimeoutPrecommit.Nanoseconds()+cfg.TimeoutPrecommitDelta.Nanoseconds()*int64(round),
) * time.Nanosecond
}

// Commit returns the amount of time to wait for straggler votes after receiving +2/3 precommits
// Commit returns the amount of time to wait for straggler votes after receiving +1/2 precommits
// for a single block (ie. a commit).
func (cfg *ConsensusConfig) Commit(t time.Time) time.Time {
return t.Add(cfg.TimeoutCommit)
Expand Down
6 changes: 3 additions & 3 deletions consensus/reactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ func (ps *PeerState) getVoteBitArray(height int64, round int, votesType types.Si
return nil
}

// 'round': A round for which we have a +2/3 commit.
// 'round': A round for which we have a +1/2 commit.
func (ps *PeerState) ensureCatchupCommitRound(height int64, round int, numValidators int) {
if ps.PRS.Height != height {
return
Expand Down Expand Up @@ -1453,7 +1453,7 @@ func (m *NewRoundStepMessage) String() string {
//-------------------------------------

// NewValidBlockMessage is sent when a validator observes a valid block B in some round r,
//i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
//i.e., there is a Proposal for block B and 1/2+ prevotes for the block B in the round r.
// In case the block is also committed, then IsCommit flag is set to true.
type NewValidBlockMessage struct {
Height int64
Expand Down Expand Up @@ -1621,7 +1621,7 @@ func (m *HasVoteMessage) String() string {

//-------------------------------------

// VoteSetMaj23Message is sent to indicate that a given BlockID has seen +2/3 votes.
// VoteSetMaj23Message is sent to indicate that a given BlockID has seen +1/2 votes.
type VoteSetMaj23Message struct {
Height int64
Round int
Expand Down
82 changes: 41 additions & 41 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ func (cs *State) reconstructLastCommit(state sm.State) {
}
lastPrecommits := types.CommitToVoteSet(state.ChainID, seenCommit, state.LastValidators)
if !lastPrecommits.HasTwoThirdsMajority() {
panic("Failed to reconstruct LastCommit: Does not have +2/3 maj")
panic("Failed to reconstruct LastCommit: Does not have +1/2 maj")
}
cs.LastCommit = lastPrecommits
}
Expand Down Expand Up @@ -548,7 +548,7 @@ func (cs *State) updateToState(state sm.State) {
lastPrecommits := (*types.VoteSet)(nil)
if cs.CommitRound > -1 && cs.Votes != nil {
if !cs.Votes.Precommits(cs.CommitRound).HasTwoThirdsMajority() {
panic("updateToState(state) called but last Precommit round didn't have +2/3")
panic("updateToState(state) called but last Precommit round didn't have +1/2")
}
lastPrecommits = cs.Votes.Precommits(cs.CommitRound)
}
Expand Down Expand Up @@ -609,7 +609,7 @@ func (cs *State) newStep() {
// receiveRoutine handles messages which may cause state transitions.
// it's argument (n) is the number of messages to process before exiting - use 0 to run forever
// It keeps the RoundState and is the only thing that updates it.
// Updates (state transitions) happen on timeouts, complete proposals, and 2/3 majorities.
// Updates (state transitions) happen on timeouts, complete proposals, and 1/2 majorities.
// State must be locked before any internal state is updated.
func (cs *State) receiveRoutine(maxSteps int) {
onExit := func(cs *State) {
Expand Down Expand Up @@ -656,7 +656,7 @@ func (cs *State) receiveRoutine(maxSteps int) {
case mi = <-cs.peerMsgQueue:
cs.wal.Write(mi)
// handles proposals, block parts, votes
// may generate internal events (votes, complete proposals, 2/3 majorities)
// may generate internal events (votes, complete proposals, 1/2 majorities)
cs.handleMsg(mi)
case mi = <-cs.internalMsgQueue:
err := cs.wal.WriteSync(mi) // NOTE: fsync
Expand Down Expand Up @@ -686,7 +686,7 @@ func (cs *State) receiveRoutine(maxSteps int) {
}
}

// state transitions on complete-proposal, 2/3-any, 2/3-one
// state transitions on complete-proposal, 1/2-any, 1/2-one
func (cs *State) handleMsg(mi msgInfo) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
Expand Down Expand Up @@ -721,7 +721,7 @@ func (cs *State) handleMsg(mi msgInfo) {
}
case *VoteMessage:
// attempt to add the vote and dupeout the validator if its a duplicate signature
// if the vote gives us a 2/3-any or 2/3-one, we transition
// if the vote gives us a 1/2-any or 1/2-one, we transition
added, err = cs.tryAddVote(msg.Vote, peerID)
if added {
cs.statsMsgQueue <- mi
Expand Down Expand Up @@ -820,9 +820,9 @@ func (cs *State) handleTxsAvailable() {

// Enter: `timeoutNewHeight` by startTime (commitTime+timeoutCommit),
// or, if SkipTimeoutCommit==true, after receiving all precommits from (height,round-1)
// Enter: `timeoutPrecommits` after any +2/3 precommits from (height,round-1)
// Enter: +2/3 precommits for nil at (height,round-1)
// Enter: +2/3 prevotes any or +2/3 precommits for block or any from (height, round)
// Enter: `timeoutPrecommits` after any +1/2 precommits from (height,round-1)
// Enter: +1/2 precommits for nil at (height,round-1)
// Enter: +1/2 prevotes any or +1/2 precommits for block or any from (height, round)
// NOTE: cs.StartTime was already set for height.
func (cs *State) enterNewRound(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
Expand Down Expand Up @@ -1015,7 +1015,7 @@ func (cs *State) defaultDecideProposal(height int64, round int) {
}

// Returns true if the proposal block is complete &&
// (if POLRound was proposed, we have +2/3 prevotes from there).
// (if POLRound was proposed, we have +1/2 prevotes from there).
func (cs *State) isProposalComplete() bool {
if cs.Proposal == nil || cs.ProposalBlock == nil {
return false
Expand Down Expand Up @@ -1094,8 +1094,8 @@ func (cs *State) enterPrevote(height int64, round int) {
// Sign and broadcast vote as necessary
cs.doPrevote(height, round)

// Once `addVote` hits any +2/3 prevotes, we will go to PrevoteWait
// (so we have more time to try and collect +2/3 prevotes for a single block)
// Once `addVote` hits any +1/2 prevotes, we will go to PrevoteWait
// (so we have more time to try and collect +1/2 prevotes for a single block)
}

func (cs *State) defaultDoPrevote(height int64, round int) {
Expand Down Expand Up @@ -1131,7 +1131,7 @@ func (cs *State) defaultDoPrevote(height int64, round int) {
cs.signAddVote(types.PrevoteType, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
}

// Enter: any +2/3 prevotes at next round.
// Enter: any +1/2 prevotes at next round.
func (cs *State) enterPrevoteWait(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)

Expand All @@ -1146,7 +1146,7 @@ func (cs *State) enterPrevoteWait(height int64, round int) {
return
}
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))
panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +1/2 votes", height, round))
}
logger.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))

Expand All @@ -1160,11 +1160,11 @@ func (cs *State) enterPrevoteWait(height int64, round int) {
cs.scheduleTimeout(cs.config.Prevote(round), height, round, cstypes.RoundStepPrevoteWait)
}

// Enter: `timeoutPrevote` after any +2/3 prevotes.
// Enter: `timeoutPrecommit` after any +2/3 precommits.
// Enter: +2/3 precomits for block or nil.
// Enter: `timeoutPrevote` after any +1/2 prevotes.
// Enter: `timeoutPrecommit` after any +1/2 precommits.
// Enter: +1/2 precomits for block or nil.
// 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, unlock an existing lock and precommit nil if +1/2 of prevotes were nil,
// else, precommit nil otherwise.
func (cs *State) enterPrecommit(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)
Expand Down Expand Up @@ -1194,15 +1194,15 @@ func (cs *State) enterPrecommit(height int64, round int) {
// If we don't have a polka, we must precommit nil.
if !ok {
if cs.LockedBlock != nil {
logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit while we're locked. Precommitting nil")
logger.Info("enterPrecommit: No +1/2 prevotes during enterPrecommit while we're locked. Precommitting nil")
} else {
logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit. Precommitting nil.")
logger.Info("enterPrecommit: No +1/2 prevotes during enterPrecommit. Precommitting nil.")
}
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
return
}

// At this point +2/3 prevoted for a particular block or nil.
// At this point +1/2 prevoted for a particular block or nil.
cs.eventBus.PublishEventPolka(cs.RoundStateEvent())

// the latest POLRound should be this round.
Expand All @@ -1211,12 +1211,12 @@ func (cs *State) enterPrecommit(height int64, round int) {
panic(fmt.Sprintf("This POLRound should be %v but got %v", round, polRound))
}

// +2/3 prevoted nil. Unlock and precommit nil.
// +1/2 prevoted nil. Unlock and precommit nil.
if len(blockID.Hash) == 0 {
if cs.LockedBlock == nil {
logger.Info("enterPrecommit: +2/3 prevoted for nil.")
logger.Info("enterPrecommit: +1/2 prevoted for nil.")
} else {
logger.Info("enterPrecommit: +2/3 prevoted for nil. Unlocking")
logger.Info("enterPrecommit: +1/2 prevoted for nil. Unlocking")
cs.LockedRound = -1
cs.LockedBlock = nil
cs.LockedBlockParts = nil
Expand All @@ -1226,23 +1226,23 @@ func (cs *State) enterPrecommit(height int64, round int) {
return
}

// At this point, +2/3 prevoted for a particular block.
// At this point, +1/2 prevoted for a particular block.

// If we're already locked on that block, precommit it, and update the LockedRound
if cs.LockedBlock.HashesTo(blockID.Hash) {
logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
logger.Info("enterPrecommit: +1/2 prevoted locked block. Relocking")
cs.LockedRound = round
cs.eventBus.PublishEventRelock(cs.RoundStateEvent())
cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
return
}

// If +2/3 prevoted for proposal block, stage and precommit it
// If +1/2 prevoted for proposal block, stage and precommit it
if cs.ProposalBlock.HashesTo(blockID.Hash) {
logger.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", blockID.Hash)
logger.Info("enterPrecommit: +1/2 prevoted proposal block. Locking", "hash", blockID.Hash)
// Validate the block.
if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
panic(fmt.Sprintf("enterPrecommit: +1/2 prevoted for an invalid block: %v", err))
}
cs.LockedRound = round
cs.LockedBlock = cs.ProposalBlock
Expand All @@ -1254,7 +1254,7 @@ func (cs *State) enterPrecommit(height int64, round int) {

// 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.
// The +1/2 prevotes for this round is the POL for our unlock.
// TODO: In the future save the POL prevotes for justification.
cs.LockedRound = -1
cs.LockedBlock = nil
Expand All @@ -1267,7 +1267,7 @@ func (cs *State) enterPrecommit(height int64, round int) {
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
}

// Enter: any +2/3 precommits for next round.
// Enter: any +1/2 precommits for next round.
func (cs *State) enterPrecommitWait(height int64, round int) {
logger := cs.Logger.With("height", height, "round", round)

Expand All @@ -1280,7 +1280,7 @@ func (cs *State) enterPrecommitWait(height int64, round int) {
return
}
if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
panic(fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round))
panic(fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +1/2 votes", height, round))
}
logger.Info(fmt.Sprintf("enterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))

Expand All @@ -1295,7 +1295,7 @@ func (cs *State) enterPrecommitWait(height int64, round int) {

}

// Enter: +2/3 precommits for block
// Enter: +1/2 precommits for block
func (cs *State) enterCommit(height int64, commitRound int) {
logger := cs.Logger.With("height", height, "commitRound", commitRound)

Expand Down Expand Up @@ -1325,7 +1325,7 @@ func (cs *State) enterCommit(height int64, commitRound int) {

blockID, ok := cs.Votes.Precommits(commitRound).TwoThirdsMajority()
if !ok {
panic("RunActionCommit() expects +2/3 precommits")
panic("RunActionCommit() expects +1/2 precommits")
}

// The Locked* fields no longer matter.
Expand Down Expand Up @@ -1359,7 +1359,7 @@ func (cs *State) enterCommit(height int64, commitRound int) {
}
}

// If we have the block AND +2/3 commits for it, finalize.
// If we have the block AND +1/2 commits for it, finalize.
func (cs *State) tryFinalizeCommit(height int64) {
logger := cs.Logger.With("height", height)

Expand All @@ -1369,7 +1369,7 @@ func (cs *State) tryFinalizeCommit(height int64) {

blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority()
if !ok || len(blockID.Hash) == 0 {
logger.Error("Attempt to finalize failed. There was no +2/3 majority, or +2/3 was for <nil>.")
logger.Error("Attempt to finalize failed. There was no +1/2 majority, or +1/2 was for <nil>.")
return
}
if !cs.ProposalBlock.HashesTo(blockID.Hash) {
Expand Down Expand Up @@ -1413,7 +1413,7 @@ func (cs *State) finalizeCommit(height int64) {
panic(fmt.Sprintf("Cannot finalizeCommit, ProposalBlock does not hash to commit hash"))
}
if err := cs.blockExec.ValidateBlock(cs.state, block); err != nil {
panic(fmt.Sprintf("+2/3 committed an invalid block: %v", err))
panic(fmt.Sprintf("+1/2 committed an invalid block: %v", err))
}

cs.Logger.Info("Finalizing commit of block with N txs",
Expand Down Expand Up @@ -1698,7 +1698,7 @@ func (cs *State) addProposalBlockPart(msg *BlockPartMessage, peerID p2p.ID) (add
cs.ValidBlock = cs.ProposalBlock
cs.ValidBlockParts = cs.ProposalBlockParts
}
// TODO: In case there is +2/3 majority in Prevotes set for some
// TODO: In case there is +1/2 majority in Prevotes set for some
// block and cs.ProposalBlock contains different block, either
// proposer is faulty or voting power of faulty processes is more
// than 1/3. We should trigger in the future accountability
Expand Down Expand Up @@ -1830,7 +1830,7 @@ func (cs *State) addVote(
prevotes := cs.Votes.Prevotes(vote.Round)
cs.Logger.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())

// If +2/3 prevotes for a block or nil for *any* round:
// If +1/2 prevotes for a block or nil for *any* round:
if blockID, ok := prevotes.TwoThirdsMajority(); ok {

// There was a polka!
Expand Down Expand Up @@ -1876,10 +1876,10 @@ func (cs *State) addVote(
}
}

// If +2/3 prevotes for *anything* for future round:
// If +1/2 prevotes for *anything* for future round:
switch {
case cs.Round < vote.Round && prevotes.HasTwoThirdsAny():
// Round-skip if there is any 2/3+ of votes ahead of us
// Round-skip if there is any 1/2+ of votes ahead of us
cs.enterNewRound(height, vote.Round)
case cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step: // current round
blockID, ok := prevotes.TwoThirdsMajority()
Expand Down
12 changes: 6 additions & 6 deletions consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ SlashingSuite
x * TestSlashingPrevotes - a validator prevoting twice in a round gets slashed
x * TestSlashingPrecommits - a validator precomitting twice in a round gets slashed
CatchupSuite
* TestCatchup - if we might be behind and we've seen any 2/3 prevotes, round skip to new round, precommit, or prevote
* TestCatchup - if we might be behind and we've seen any 1/2 prevotes, round skip to new round, precommit, or prevote
HaltSuite
x * TestHalt1 - if we see +2/3 precommits after timing out into new round, we should still commit
x * TestHalt1 - if we see +1/2 precommits after timing out into new round, we should still commit

*/

Expand Down Expand Up @@ -534,7 +534,7 @@ func TestStateLockPOLRelock(t *testing.T) {
/*
Round1 (cs1, B) // B B B B// B nil B nil

eg. vs2 and vs4 didn't see the 2/3 prevotes
eg. vs2 and vs4 didn't see the 1/2 prevotes
*/

// start round and wait for propose and prevote
Expand Down Expand Up @@ -626,7 +626,7 @@ func TestStateLockPOLUnlock(t *testing.T) {
/*
Round1 (cs1, B) // B B B B // B nil B nil

eg. didn't see the 2/3 prevotes
eg. didn't see the 1/2 prevotes
*/

// start round and wait for propose and prevote
Expand Down Expand Up @@ -1238,7 +1238,7 @@ func TestWaitTimeoutProposeOnNilPolkaForTheCurrentRound(t *testing.T) {
}

// What we want:
// P0 emit NewValidBlock event upon receiving 2/3+ Precommit for B but hasn't received block B yet
// P0 emit NewValidBlock event upon receiving 1/2+ Precommit for B but hasn't received block B yet
func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) {
cs1, vss := randState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
Expand Down Expand Up @@ -1271,7 +1271,7 @@ func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) {
}

// What we want:
// P0 receives 2/3+ Precommit for B for round 0, while being in round 1. It emits NewValidBlock event.
// P0 receives 1/2+ Precommit for B for round 0, while being in round 1. It emits NewValidBlock event.
// After receiving block, it executes block and moves to the next height.
func TestCommitFromPreviousRound(t *testing.T) {
cs1, vss := randState(4)
Expand Down
Loading