|
@ -54,7 +54,7 @@ type msgInfo struct { |
|
|
// internally generated messages which may update the state
|
|
|
// internally generated messages which may update the state
|
|
|
type timeoutInfo struct { |
|
|
type timeoutInfo struct { |
|
|
Duration time.Duration `json:"duration"` |
|
|
Duration time.Duration `json:"duration"` |
|
|
Height int `json:"height"` |
|
|
|
|
|
|
|
|
Height int64 `json:"height"` |
|
|
Round int `json:"round"` |
|
|
Round int `json:"round"` |
|
|
Step cstypes.RoundStepType `json:"step"` |
|
|
Step cstypes.RoundStepType `json:"step"` |
|
|
} |
|
|
} |
|
@ -104,8 +104,8 @@ type ConsensusState struct { |
|
|
nSteps int |
|
|
nSteps int |
|
|
|
|
|
|
|
|
// some functions can be overwritten for testing
|
|
|
// some functions can be overwritten for testing
|
|
|
decideProposal func(height, round int) |
|
|
|
|
|
doPrevote func(height, round int) |
|
|
|
|
|
|
|
|
decideProposal func(height int64, round int) |
|
|
|
|
|
doPrevote func(height int64, round int) |
|
|
setProposal func(proposal *types.Proposal) error |
|
|
setProposal func(proposal *types.Proposal) error |
|
|
|
|
|
|
|
|
// closed when we finish shutting down
|
|
|
// closed when we finish shutting down
|
|
@ -179,7 +179,7 @@ func (cs *ConsensusState) getRoundState() *cstypes.RoundState { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// GetValidators returns a copy of the current validators.
|
|
|
// GetValidators returns a copy of the current validators.
|
|
|
func (cs *ConsensusState) GetValidators() (int, []*types.Validator) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) { |
|
|
cs.mtx.Lock() |
|
|
cs.mtx.Lock() |
|
|
defer cs.mtx.Unlock() |
|
|
defer cs.mtx.Unlock() |
|
|
return cs.state.LastBlockHeight, cs.state.Validators.Copy().Validators |
|
|
return cs.state.LastBlockHeight, cs.state.Validators.Copy().Validators |
|
@ -200,7 +200,7 @@ func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// LoadCommit loads the commit for a given height.
|
|
|
// LoadCommit loads the commit for a given height.
|
|
|
func (cs *ConsensusState) LoadCommit(height int) *types.Commit { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) LoadCommit(height int64) *types.Commit { |
|
|
cs.mtx.Lock() |
|
|
cs.mtx.Lock() |
|
|
defer cs.mtx.Unlock() |
|
|
defer cs.mtx.Unlock() |
|
|
if height == cs.blockStore.Height() { |
|
|
if height == cs.blockStore.Height() { |
|
@ -331,7 +331,7 @@ func (cs *ConsensusState) SetProposal(proposal *types.Proposal, peerKey string) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// AddProposalBlockPart inputs a part of the proposal block.
|
|
|
// AddProposalBlockPart inputs a part of the proposal block.
|
|
|
func (cs *ConsensusState) AddProposalBlockPart(height, round int, part *types.Part, peerKey string) error { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) AddProposalBlockPart(height int64, round int, part *types.Part, peerKey string) error { |
|
|
|
|
|
|
|
|
if peerKey == "" { |
|
|
if peerKey == "" { |
|
|
cs.internalMsgQueue <- msgInfo{&BlockPartMessage{height, round, part}, ""} |
|
|
cs.internalMsgQueue <- msgInfo{&BlockPartMessage{height, round, part}, ""} |
|
@ -360,7 +360,7 @@ func (cs *ConsensusState) SetProposalAndBlock(proposal *types.Proposal, block *t |
|
|
//------------------------------------------------------------
|
|
|
//------------------------------------------------------------
|
|
|
// internal functions for managing the state
|
|
|
// internal functions for managing the state
|
|
|
|
|
|
|
|
|
func (cs *ConsensusState) updateHeight(height int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) updateHeight(height int64) { |
|
|
cs.Height = height |
|
|
cs.Height = height |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -377,7 +377,7 @@ func (cs *ConsensusState) scheduleRound0(rs *cstypes.RoundState) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Attempt to schedule a timeout (by sending timeoutInfo on the tickChan)
|
|
|
// Attempt to schedule a timeout (by sending timeoutInfo on the tickChan)
|
|
|
func (cs *ConsensusState) scheduleTimeout(duration time.Duration, height, round int, step cstypes.RoundStepType) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) scheduleTimeout(duration time.Duration, height int64, round int, step cstypes.RoundStepType) { |
|
|
cs.timeoutTicker.ScheduleTimeout(timeoutInfo{duration, height, round, step}) |
|
|
cs.timeoutTicker.ScheduleTimeout(timeoutInfo{duration, height, round, step}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -627,7 +627,7 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) { |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) handleTxsAvailable(height int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) handleTxsAvailable(height int64) { |
|
|
cs.mtx.Lock() |
|
|
cs.mtx.Lock() |
|
|
defer cs.mtx.Unlock() |
|
|
defer cs.mtx.Unlock() |
|
|
// we only need to do this for round 0
|
|
|
// we only need to do this for round 0
|
|
@ -644,7 +644,7 @@ func (cs *ConsensusState) handleTxsAvailable(height int) { |
|
|
// Enter: +2/3 precommits for nil at (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: +2/3 prevotes any or +2/3 precommits for block or any from (height, round)
|
|
|
// NOTE: cs.StartTime was already set for height.
|
|
|
// NOTE: cs.StartTime was already set for height.
|
|
|
func (cs *ConsensusState) enterNewRound(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterNewRound(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != cstypes.RoundStepNewHeight) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != cstypes.RoundStepNewHeight) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -697,7 +697,7 @@ func (cs *ConsensusState) enterNewRound(height int, round int) { |
|
|
|
|
|
|
|
|
// needProofBlock returns true on the first height (so the genesis app hash is signed right away)
|
|
|
// needProofBlock returns true on the first height (so the genesis app hash is signed right away)
|
|
|
// and where the last block (height-1) caused the app hash to change
|
|
|
// and where the last block (height-1) caused the app hash to change
|
|
|
func (cs *ConsensusState) needProofBlock(height int) bool { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) needProofBlock(height int64) bool { |
|
|
if height == 1 { |
|
|
if height == 1 { |
|
|
return true |
|
|
return true |
|
|
} |
|
|
} |
|
@ -706,7 +706,7 @@ func (cs *ConsensusState) needProofBlock(height int) bool { |
|
|
return !bytes.Equal(cs.state.AppHash, lastBlockMeta.Header.AppHash) |
|
|
return !bytes.Equal(cs.state.AppHash, lastBlockMeta.Header.AppHash) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) proposalHeartbeat(height, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) proposalHeartbeat(height int64, round int) { |
|
|
counter := 0 |
|
|
counter := 0 |
|
|
addr := cs.privValidator.GetAddress() |
|
|
addr := cs.privValidator.GetAddress() |
|
|
valIndex, v := cs.Validators.GetByAddress(addr) |
|
|
valIndex, v := cs.Validators.GetByAddress(addr) |
|
@ -738,7 +738,7 @@ func (cs *ConsensusState) proposalHeartbeat(height, round int) { |
|
|
// Enter (CreateEmptyBlocks): from enterNewRound(height,round)
|
|
|
// Enter (CreateEmptyBlocks): from enterNewRound(height,round)
|
|
|
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
|
|
|
// Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
|
|
|
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
|
|
|
// Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
|
|
|
func (cs *ConsensusState) enterPropose(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterPropose(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPropose <= cs.Step) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPropose <= cs.Step) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -785,7 +785,7 @@ func (cs *ConsensusState) isProposer() bool { |
|
|
return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.GetAddress()) |
|
|
return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.GetAddress()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) defaultDecideProposal(height, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) defaultDecideProposal(height int64, round int) { |
|
|
var block *types.Block |
|
|
var block *types.Block |
|
|
var blockParts *types.PartSet |
|
|
var blockParts *types.PartSet |
|
|
|
|
|
|
|
@ -873,7 +873,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts |
|
|
// Enter: any +2/3 prevotes for future round.
|
|
|
// Enter: any +2/3 prevotes for future round.
|
|
|
// Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
|
|
|
// Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
|
|
|
// Otherwise vote nil.
|
|
|
// Otherwise vote nil.
|
|
|
func (cs *ConsensusState) enterPrevote(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterPrevote(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -902,7 +902,7 @@ func (cs *ConsensusState) enterPrevote(height int, round int) { |
|
|
// (so we have more time to try and collect +2/3 prevotes for a single block)
|
|
|
// (so we have more time to try and collect +2/3 prevotes for a single block)
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) defaultDoPrevote(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) defaultDoPrevote(height int64, round int) { |
|
|
logger := cs.Logger.With("height", height, "round", round) |
|
|
logger := cs.Logger.With("height", height, "round", round) |
|
|
// If a block is locked, prevote that.
|
|
|
// If a block is locked, prevote that.
|
|
|
if cs.LockedBlock != nil { |
|
|
if cs.LockedBlock != nil { |
|
@ -935,7 +935,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int, round int) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Enter: any +2/3 prevotes at next round.
|
|
|
// Enter: any +2/3 prevotes at next round.
|
|
|
func (cs *ConsensusState) enterPrevoteWait(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterPrevoteWait(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -961,7 +961,7 @@ func (cs *ConsensusState) enterPrevoteWait(height int, round int) { |
|
|
// Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this 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, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
|
|
|
// else, precommit nil otherwise.
|
|
|
// else, precommit nil otherwise.
|
|
|
func (cs *ConsensusState) enterPrecommit(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterPrecommit(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -1054,7 +1054,7 @@ func (cs *ConsensusState) enterPrecommit(height int, round int) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Enter: any +2/3 precommits for next round.
|
|
|
// Enter: any +2/3 precommits for next round.
|
|
|
func (cs *ConsensusState) enterPrecommitWait(height int, round int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterPrecommitWait(height int64, round int) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommitWait <= cs.Step) { |
|
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommitWait <= cs.Step) { |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -1076,7 +1076,7 @@ func (cs *ConsensusState) enterPrecommitWait(height int, round int) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Enter: +2/3 precommits for block
|
|
|
// Enter: +2/3 precommits for block
|
|
|
func (cs *ConsensusState) enterCommit(height int, commitRound int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) enterCommit(height int64, commitRound int) { |
|
|
if cs.Height != height || cstypes.RoundStepCommit <= cs.Step { |
|
|
if cs.Height != height || cstypes.RoundStepCommit <= cs.Step { |
|
|
cs.Logger.Debug(cmn.Fmt("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -1122,7 +1122,7 @@ func (cs *ConsensusState) enterCommit(height int, commitRound int) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If we have the block AND +2/3 commits for it, finalize.
|
|
|
// If we have the block AND +2/3 commits for it, finalize.
|
|
|
func (cs *ConsensusState) tryFinalizeCommit(height int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) tryFinalizeCommit(height int64) { |
|
|
if cs.Height != height { |
|
|
if cs.Height != height { |
|
|
cmn.PanicSanity(cmn.Fmt("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height)) |
|
|
cmn.PanicSanity(cmn.Fmt("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height)) |
|
|
} |
|
|
} |
|
@ -1144,7 +1144,7 @@ func (cs *ConsensusState) tryFinalizeCommit(height int) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Increment height and goto cstypes.RoundStepNewHeight
|
|
|
// Increment height and goto cstypes.RoundStepNewHeight
|
|
|
func (cs *ConsensusState) finalizeCommit(height int) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) finalizeCommit(height int64) { |
|
|
if cs.Height != height || cs.Step != cstypes.RoundStepCommit { |
|
|
if cs.Height != height || cs.Step != cstypes.RoundStepCommit { |
|
|
cs.Logger.Debug(cmn.Fmt("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) |
|
|
cs.Logger.Debug(cmn.Fmt("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) |
|
|
return |
|
|
return |
|
@ -1193,7 +1193,7 @@ func (cs *ConsensusState) finalizeCommit(height int) { |
|
|
// WAL replay for blocks with an #ENDHEIGHT
|
|
|
// WAL replay for blocks with an #ENDHEIGHT
|
|
|
// As is, ConsensusState should not be started again
|
|
|
// As is, ConsensusState should not be started again
|
|
|
// until we successfully call ApplyBlock (ie. here or in Handshake after restart)
|
|
|
// until we successfully call ApplyBlock (ie. here or in Handshake after restart)
|
|
|
cs.wal.Save(EndHeightMessage{uint64(height)}) |
|
|
|
|
|
|
|
|
cs.wal.Save(EndHeightMessage{height}) |
|
|
|
|
|
|
|
|
fail.Fail() // XXX
|
|
|
fail.Fail() // XXX
|
|
|
|
|
|
|
|
@ -1285,7 +1285,7 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error { |
|
|
|
|
|
|
|
|
// NOTE: block is not necessarily valid.
|
|
|
// NOTE: block is not necessarily valid.
|
|
|
// Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit, once we have the full block.
|
|
|
// Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit, once we have the full block.
|
|
|
func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, verify bool) (added bool, err error) { |
|
|
|
|
|
|
|
|
func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, verify bool) (added bool, err error) { |
|
|
// Blocks might be reused, so round mismatch is OK
|
|
|
// Blocks might be reused, so round mismatch is OK
|
|
|
if cs.Height != height { |
|
|
if cs.Height != height { |
|
|
return false, nil |
|
|
return false, nil |
|
@ -1494,7 +1494,7 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.Part |
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
func CompareHRS(h1, r1 int, s1 cstypes.RoundStepType, h2, r2 int, s2 cstypes.RoundStepType) int { |
|
|
|
|
|
|
|
|
func CompareHRS(h1 int64, r1 int, s1 cstypes.RoundStepType, h2 int64, r2 int, s2 cstypes.RoundStepType) int { |
|
|
if h1 < h2 { |
|
|
if h1 < h2 { |
|
|
return -1 |
|
|
return -1 |
|
|
} else if h1 > h2 { |
|
|
} else if h1 > h2 { |
|
|