mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
removed commitTime from VoteSet.
This commit is contained in:
parent
89418ee7af
commit
bccf0afe00
@ -92,6 +92,12 @@ func calcRoundInfo(startTime time.Time) (round uint16, roundStartTime time.Time,
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type RoundAction struct {
|
||||||
|
Height uint32 // The block height for which consensus is reaching for.
|
||||||
|
Round uint16 // The round number at given height.
|
||||||
|
Action RoundActionType // Action to perform.
|
||||||
|
}
|
||||||
|
|
||||||
type ConsensusReactor struct {
|
type ConsensusReactor struct {
|
||||||
sw *p2p.Switch
|
sw *p2p.Switch
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
@ -241,9 +247,9 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
|||||||
}
|
}
|
||||||
if added {
|
if added {
|
||||||
// Maybe send HasVotesMessage
|
// Maybe send HasVotesMessage
|
||||||
|
// TODO optimize. It would be better to just acks for each vote!
|
||||||
voteAddCounter++
|
voteAddCounter++
|
||||||
if voteAddCounter%hasVotesThreshold == 0 {
|
if voteAddCounter%hasVotesThreshold == 0 {
|
||||||
// TODO optimize.
|
|
||||||
msg := &HasVotesMessage{
|
msg := &HasVotesMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
Round: rs.Round,
|
Round: rs.Round,
|
||||||
@ -274,56 +280,50 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
type RoundAction struct {
|
|
||||||
Height uint32 // The block height for which consensus is reaching for.
|
|
||||||
Round uint16 // The round number at given height.
|
|
||||||
Action RoundActionType // Action to perform.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source of all round state transitions (and votes).
|
// Source of all round state transitions (and votes).
|
||||||
// It can be preemptively woken up via a message to
|
|
||||||
// doActionCh.
|
|
||||||
func (conR *ConsensusReactor) stepTransitionRoutine() {
|
func (conR *ConsensusReactor) stepTransitionRoutine() {
|
||||||
|
|
||||||
|
// Schedule the next action by pushing a RoundAction{} to conR.doActionCh
|
||||||
|
// when it is due.
|
||||||
scheduleNextAction := func() {
|
scheduleNextAction := func() {
|
||||||
// Figure out which height/round/step we're at,
|
|
||||||
// then schedule an action for when it is due.
|
|
||||||
rs := conR.conS.GetRoundState()
|
rs := conR.conS.GetRoundState()
|
||||||
_, _, roundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime)
|
_, _, roundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime)
|
||||||
switch rs.Step {
|
go func() {
|
||||||
case RoundStepStart:
|
switch rs.Step {
|
||||||
// It's a new RoundState.
|
case RoundStepStart:
|
||||||
if elapsedRatio < 0 {
|
// It's a new RoundState.
|
||||||
// startTime is in the future.
|
if elapsedRatio < 0 {
|
||||||
time.Sleep(time.Duration(-1.0*elapsedRatio) * roundDuration)
|
// startTime is in the future.
|
||||||
|
time.Sleep(time.Duration(-1.0*elapsedRatio) * roundDuration)
|
||||||
|
}
|
||||||
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
|
||||||
|
case RoundStepPropose:
|
||||||
|
// Wake up when it's time to vote.
|
||||||
|
time.Sleep(time.Duration(roundDeadlinePrevote-elapsedRatio) * roundDuration)
|
||||||
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrevote}
|
||||||
|
case RoundStepPrevote:
|
||||||
|
// Wake up when it's time to precommit.
|
||||||
|
time.Sleep(time.Duration(roundDeadlinePrecommit-elapsedRatio) * roundDuration)
|
||||||
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrecommit}
|
||||||
|
case RoundStepPrecommit:
|
||||||
|
// Wake up when the round is over.
|
||||||
|
time.Sleep(time.Duration(1.0-elapsedRatio) * roundDuration)
|
||||||
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionNextRound}
|
||||||
|
case RoundStepCommit:
|
||||||
|
panic("Should not happen: RoundStepCommit waits until +2/3 commits.")
|
||||||
|
case RoundStepCommitWait:
|
||||||
|
// Wake up when it's time to finalize commit.
|
||||||
|
if rs.CommitTime.IsZero() {
|
||||||
|
panic("RoundStepCommitWait requires rs.CommitTime")
|
||||||
|
}
|
||||||
|
time.Sleep(rs.CommitTime.Sub(time.Now()) + finalizeDuration)
|
||||||
|
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionFinalize}
|
||||||
|
default:
|
||||||
|
panic("Should not happen")
|
||||||
}
|
}
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
|
}()
|
||||||
case RoundStepPropose:
|
|
||||||
// Wake up when it's time to vote.
|
|
||||||
time.Sleep(time.Duration(roundDeadlinePrevote-elapsedRatio) * roundDuration)
|
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrevote}
|
|
||||||
case RoundStepPrevote:
|
|
||||||
// Wake up when it's time to precommit.
|
|
||||||
time.Sleep(time.Duration(roundDeadlinePrecommit-elapsedRatio) * roundDuration)
|
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrecommit}
|
|
||||||
case RoundStepPrecommit:
|
|
||||||
// Wake up when the round is over.
|
|
||||||
time.Sleep(time.Duration(1.0-elapsedRatio) * roundDuration)
|
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionNextRound}
|
|
||||||
case RoundStepCommit:
|
|
||||||
panic("Should not happen: RoundStepCommit waits until +2/3 commits.")
|
|
||||||
case RoundStepCommitWait:
|
|
||||||
// Wake up when it's time to finalize commit.
|
|
||||||
if rs.CommitTime.IsZero() {
|
|
||||||
panic("RoundStepCommitWait requires rs.CommitTime")
|
|
||||||
}
|
|
||||||
time.Sleep(rs.CommitTime.Sub(time.Now()) + finalizeDuration)
|
|
||||||
conR.doActionCh <- RoundAction{rs.Height, rs.Round, RoundActionFinalize}
|
|
||||||
default:
|
|
||||||
panic("Should not happen")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
@ -435,7 +435,7 @@ ACTION_LOOP:
|
|||||||
if rs.Step >= RoundStepCommitWait {
|
if rs.Step >= RoundStepCommitWait {
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
}
|
}
|
||||||
// First we must commit.
|
// Commit first we haven't already.
|
||||||
if rs.Step < RoundStepCommit {
|
if rs.Step < RoundStepCommit {
|
||||||
// NOTE: Duplicated in RoundActionCommit.
|
// NOTE: Duplicated in RoundActionCommit.
|
||||||
hash := conR.conS.RunActionCommit(rs.Height)
|
hash := conR.conS.RunActionCommit(rs.Height)
|
||||||
@ -451,7 +451,7 @@ ACTION_LOOP:
|
|||||||
panic("This shouldn't happen")
|
panic("This shouldn't happen")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now wait for more commit votes.
|
// Wait for more commit votes.
|
||||||
conR.conS.RunActionCommitWait(rs.Height)
|
conR.conS.RunActionCommitWait(rs.Height)
|
||||||
scheduleNextAction()
|
scheduleNextAction()
|
||||||
continue ACTION_LOOP
|
continue ACTION_LOOP
|
||||||
@ -474,7 +474,16 @@ ACTION_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
func (conR *ConsensusReactor) signAndBroadcastVote(rs *RoundState, vote *Vote) {
|
||||||
|
if rs.PrivValidator != nil {
|
||||||
|
rs.PrivValidator.Sign(vote)
|
||||||
|
conR.conS.AddVote(vote)
|
||||||
|
msg := p2p.TypedMessage{msgTypeVote, vote}
|
||||||
|
conR.sw.Broadcast(VoteCh, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------
|
||||||
|
|
||||||
func (conR *ConsensusReactor) gossipDataRoutine(peer *p2p.Peer, ps *PeerState) {
|
func (conR *ConsensusReactor) gossipDataRoutine(peer *p2p.Peer, ps *PeerState) {
|
||||||
|
|
||||||
@ -540,8 +549,6 @@ OUTER_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
func (conR *ConsensusReactor) gossipVotesRoutine(peer *p2p.Peer, ps *PeerState) {
|
func (conR *ConsensusReactor) gossipVotesRoutine(peer *p2p.Peer, ps *PeerState) {
|
||||||
OUTER_LOOP:
|
OUTER_LOOP:
|
||||||
for {
|
for {
|
||||||
@ -621,16 +628,6 @@ OUTER_LOOP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signs a vote document and broadcasts it.
|
|
||||||
func (conR *ConsensusReactor) signAndBroadcastVote(rs *RoundState, vote *Vote) {
|
|
||||||
if rs.PrivValidator != nil {
|
|
||||||
rs.PrivValidator.Sign(vote)
|
|
||||||
conR.conS.AddVote(vote)
|
|
||||||
msg := p2p.TypedMessage{msgTypeVote, vote}
|
|
||||||
conR.sw.Broadcast(VoteCh, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Read only when returned by PeerState.GetRoundState().
|
// Read only when returned by PeerState.GetRoundState().
|
||||||
|
@ -222,30 +222,7 @@ func (cs *ConsensusState) SetPrivValidator(priv *PrivValidator) {
|
|||||||
cs.PrivValidator = priv
|
cs.PrivValidator = priv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
|
//-----------------------------------------------------------------------------
|
||||||
cs.mtx.Lock()
|
|
||||||
defer cs.mtx.Unlock()
|
|
||||||
|
|
||||||
// Already have one
|
|
||||||
if cs.Proposal != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalid.
|
|
||||||
if proposal.Height != cs.Height || proposal.Round != cs.Round {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify signature
|
|
||||||
if !cs.Validators.Proposer().Verify(proposal) {
|
|
||||||
return ErrInvalidProposalSignature
|
|
||||||
}
|
|
||||||
|
|
||||||
cs.Proposal = proposal
|
|
||||||
cs.ProposalBlockPartSet = NewPartSetFromMetadata(proposal.BlockPartsTotal, proposal.BlockPartsHash)
|
|
||||||
cs.ProposalPOLPartSet = NewPartSetFromMetadata(proposal.POLPartsTotal, proposal.POLPartsHash)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
@ -321,61 +298,6 @@ func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
|
|||||||
cs.ProposalPOLPartSet = polPartSet
|
cs.ProposalPOLPartSet = polPartSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: block is not necessarily valid.
|
|
||||||
func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
|
||||||
cs.mtx.Lock()
|
|
||||||
defer cs.mtx.Unlock()
|
|
||||||
|
|
||||||
// Blocks might be reused, so round mismatch is OK
|
|
||||||
if cs.Height != height {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not expecting a block part.
|
|
||||||
if cs.ProposalBlockPartSet != nil {
|
|
||||||
return false, nil // TODO: bad peer? Return error?
|
|
||||||
}
|
|
||||||
|
|
||||||
added, err = cs.ProposalBlockPartSet.AddPart(part)
|
|
||||||
if err != nil {
|
|
||||||
return added, err
|
|
||||||
}
|
|
||||||
if added && cs.ProposalBlockPartSet.IsComplete() {
|
|
||||||
var n int64
|
|
||||||
var err error
|
|
||||||
cs.ProposalBlock = ReadBlock(cs.ProposalBlockPartSet.GetReader(), &n, &err)
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: POL is not necessarily valid.
|
|
||||||
func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
|
||||||
cs.mtx.Lock()
|
|
||||||
defer cs.mtx.Unlock()
|
|
||||||
|
|
||||||
if cs.Height != height || cs.Round != round {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not expecting a POL part.
|
|
||||||
if cs.ProposalPOLPartSet != nil {
|
|
||||||
return false, nil // TODO: bad peer? Return error?
|
|
||||||
}
|
|
||||||
|
|
||||||
added, err = cs.ProposalPOLPartSet.AddPart(part)
|
|
||||||
if err != nil {
|
|
||||||
return added, err
|
|
||||||
}
|
|
||||||
if added && cs.ProposalPOLPartSet.IsComplete() {
|
|
||||||
var n int64
|
|
||||||
var err error
|
|
||||||
cs.ProposalPOL = ReadPOL(cs.ProposalPOLPartSet.GetReader(), &n, &err)
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) []byte {
|
func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) []byte {
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
defer cs.mtx.Unlock()
|
defer cs.mtx.Unlock()
|
||||||
@ -399,24 +321,6 @@ func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) []byte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) AddVote(vote *Vote) (added bool, err error) {
|
|
||||||
switch vote.Type {
|
|
||||||
case VoteTypePrevote:
|
|
||||||
// Prevotes checks for height+round match.
|
|
||||||
return cs.Prevotes.Add(vote)
|
|
||||||
case VoteTypePrecommit:
|
|
||||||
// Precommits checks for height+round match.
|
|
||||||
return cs.Precommits.Add(vote)
|
|
||||||
case VoteTypeCommit:
|
|
||||||
// Commits checks for height match.
|
|
||||||
cs.Prevotes.Add(vote)
|
|
||||||
cs.Precommits.Add(vote)
|
|
||||||
return cs.Commits.Add(vote)
|
|
||||||
default:
|
|
||||||
panic("Unknown vote type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock the ProposalBlock if we have enough prevotes for it,
|
// Lock the ProposalBlock if we have enough prevotes for it,
|
||||||
// or unlock an existing lock if +2/3 of prevotes were nil.
|
// or unlock an existing lock if +2/3 of prevotes were nil.
|
||||||
// Returns a blockhash if a block was locked.
|
// Returns a blockhash if a block was locked.
|
||||||
@ -428,7 +332,7 @@ func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) []byte
|
|||||||
}
|
}
|
||||||
cs.Step = RoundStepPrecommit
|
cs.Step = RoundStepPrecommit
|
||||||
|
|
||||||
if hash, _, ok := cs.Prevotes.TwoThirdsMajority(); ok {
|
if hash, ok := cs.Prevotes.TwoThirdsMajority(); ok {
|
||||||
|
|
||||||
// Remember this POL. (hash may be nil)
|
// Remember this POL. (hash may be nil)
|
||||||
cs.LockedPOL = cs.Prevotes.MakePOL()
|
cs.LockedPOL = cs.Prevotes.MakePOL()
|
||||||
@ -477,7 +381,7 @@ func (cs *ConsensusState) RunActionCommit(height uint32) []byte {
|
|||||||
}
|
}
|
||||||
cs.Step = RoundStepCommit
|
cs.Step = RoundStepCommit
|
||||||
|
|
||||||
if hash, _, ok := cs.Precommits.TwoThirdsMajority(); ok {
|
if hash, ok := cs.Precommits.TwoThirdsMajority(); ok {
|
||||||
|
|
||||||
// There are some strange cases that shouldn't happen
|
// There are some strange cases that shouldn't happen
|
||||||
// (unless voters are duplicitous).
|
// (unless voters are duplicitous).
|
||||||
@ -534,9 +438,8 @@ func (cs *ConsensusState) RunActionCommitWait(height uint32) {
|
|||||||
}
|
}
|
||||||
cs.Step = RoundStepCommitWait
|
cs.Step = RoundStepCommitWait
|
||||||
|
|
||||||
if _, commitTime, ok := cs.Commits.TwoThirdsMajority(); ok {
|
if cs.Commits.HasTwoThirdsMajority() {
|
||||||
// Remember the commitTime.
|
cs.CommitTime = time.Now()
|
||||||
cs.CommitTime = commitTime
|
|
||||||
} else {
|
} else {
|
||||||
panic("RunActionCommitWait() expects +2/3 commits")
|
panic("RunActionCommitWait() expects +2/3 commits")
|
||||||
}
|
}
|
||||||
@ -553,6 +456,106 @@ func (cs *ConsensusState) RunActionFinalize(height uint32) {
|
|||||||
cs.updateToState(cs.stagedState)
|
cs.updateToState(cs.stagedState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
|
||||||
|
cs.mtx.Lock()
|
||||||
|
defer cs.mtx.Unlock()
|
||||||
|
|
||||||
|
// Already have one
|
||||||
|
if cs.Proposal != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid.
|
||||||
|
if proposal.Height != cs.Height || proposal.Round != cs.Round {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify signature
|
||||||
|
if !cs.Validators.Proposer().Verify(proposal) {
|
||||||
|
return ErrInvalidProposalSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.Proposal = proposal
|
||||||
|
cs.ProposalBlockPartSet = NewPartSetFromMetadata(proposal.BlockPartsTotal, proposal.BlockPartsHash)
|
||||||
|
cs.ProposalPOLPartSet = NewPartSetFromMetadata(proposal.POLPartsTotal, proposal.POLPartsHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: block is not necessarily valid.
|
||||||
|
func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
||||||
|
cs.mtx.Lock()
|
||||||
|
defer cs.mtx.Unlock()
|
||||||
|
|
||||||
|
// Blocks might be reused, so round mismatch is OK
|
||||||
|
if cs.Height != height {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not expecting a block part.
|
||||||
|
if cs.ProposalBlockPartSet != nil {
|
||||||
|
return false, nil // TODO: bad peer? Return error?
|
||||||
|
}
|
||||||
|
|
||||||
|
added, err = cs.ProposalBlockPartSet.AddPart(part)
|
||||||
|
if err != nil {
|
||||||
|
return added, err
|
||||||
|
}
|
||||||
|
if added && cs.ProposalBlockPartSet.IsComplete() {
|
||||||
|
var n int64
|
||||||
|
var err error
|
||||||
|
cs.ProposalBlock = ReadBlock(cs.ProposalBlockPartSet.GetReader(), &n, &err)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: POL is not necessarily valid.
|
||||||
|
func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *Part) (added bool, err error) {
|
||||||
|
cs.mtx.Lock()
|
||||||
|
defer cs.mtx.Unlock()
|
||||||
|
|
||||||
|
if cs.Height != height || cs.Round != round {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not expecting a POL part.
|
||||||
|
if cs.ProposalPOLPartSet != nil {
|
||||||
|
return false, nil // TODO: bad peer? Return error?
|
||||||
|
}
|
||||||
|
|
||||||
|
added, err = cs.ProposalPOLPartSet.AddPart(part)
|
||||||
|
if err != nil {
|
||||||
|
return added, err
|
||||||
|
}
|
||||||
|
if added && cs.ProposalPOLPartSet.IsComplete() {
|
||||||
|
var n int64
|
||||||
|
var err error
|
||||||
|
cs.ProposalPOL = ReadPOL(cs.ProposalPOLPartSet.GetReader(), &n, &err)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *ConsensusState) AddVote(vote *Vote) (added bool, err error) {
|
||||||
|
switch vote.Type {
|
||||||
|
case VoteTypePrevote:
|
||||||
|
// Prevotes checks for height+round match.
|
||||||
|
return cs.Prevotes.Add(vote)
|
||||||
|
case VoteTypePrecommit:
|
||||||
|
// Precommits checks for height+round match.
|
||||||
|
return cs.Precommits.Add(vote)
|
||||||
|
case VoteTypeCommit:
|
||||||
|
// Commits checks for height match.
|
||||||
|
cs.Prevotes.Add(vote)
|
||||||
|
cs.Precommits.Add(vote)
|
||||||
|
return cs.Commits.Add(vote)
|
||||||
|
default:
|
||||||
|
panic("Unknown vote type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) stageBlock(block *Block) error {
|
func (cs *ConsensusState) stageBlock(block *Block) error {
|
||||||
|
|
||||||
// Already staged?
|
// Already staged?
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
. "github.com/tendermint/tendermint/blocks"
|
. "github.com/tendermint/tendermint/blocks"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
@ -23,14 +22,14 @@ type VoteSet struct {
|
|||||||
round uint16
|
round uint16
|
||||||
type_ byte
|
type_ byte
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
vset *state.ValidatorSet
|
vset *state.ValidatorSet
|
||||||
votes map[uint64]*Vote
|
votes map[uint64]*Vote
|
||||||
votesBitArray BitArray
|
votesBitArray BitArray
|
||||||
votesByBlockHash map[string]uint64
|
votesByBlockHash map[string]uint64
|
||||||
totalVotes uint64
|
totalVotes uint64
|
||||||
twoThirdsMajority []byte
|
twoThirdsMajority []byte
|
||||||
twoThirdsCommitTime time.Time
|
twoThirdsExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a new VoteSet struct used to accumulate votes for each round.
|
// Constructs a new VoteSet struct used to accumulate votes for each round.
|
||||||
@ -105,7 +104,7 @@ func (vs *VoteSet) addVote(vote *Vote) (bool, error) {
|
|||||||
if totalBlockHashVotes > vs.vset.TotalVotingPower()*2/3 &&
|
if totalBlockHashVotes > vs.vset.TotalVotingPower()*2/3 &&
|
||||||
(totalBlockHashVotes-val.VotingPower) <= vs.vset.TotalVotingPower()*2/3 {
|
(totalBlockHashVotes-val.VotingPower) <= vs.vset.TotalVotingPower()*2/3 {
|
||||||
vs.twoThirdsMajority = vote.BlockHash
|
vs.twoThirdsMajority = vote.BlockHash
|
||||||
vs.twoThirdsCommitTime = time.Now()
|
vs.twoThirdsExists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -149,18 +148,19 @@ func (vs *VoteSet) HasTwoThirdsMajority() bool {
|
|||||||
}
|
}
|
||||||
vs.mtx.Lock()
|
vs.mtx.Lock()
|
||||||
defer vs.mtx.Unlock()
|
defer vs.mtx.Unlock()
|
||||||
return !vs.twoThirdsCommitTime.IsZero()
|
return vs.twoThirdsExists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns either a blockhash (or nil) that received +2/3 majority.
|
// Returns either a blockhash (or nil) that received +2/3 majority.
|
||||||
// If there exists no such majority, returns (nil, false).
|
// If there exists no such majority, returns (nil, false).
|
||||||
func (vs *VoteSet) TwoThirdsMajority() (hash []byte, commitTime time.Time, ok bool) {
|
func (vs *VoteSet) TwoThirdsMajority() (hash []byte, ok bool) {
|
||||||
vs.mtx.Lock()
|
vs.mtx.Lock()
|
||||||
defer vs.mtx.Unlock()
|
defer vs.mtx.Unlock()
|
||||||
if vs.twoThirdsCommitTime.IsZero() {
|
if vs.twoThirdsExists {
|
||||||
return nil, time.Time{}, false
|
return vs.twoThirdsMajority, true
|
||||||
|
} else {
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
return vs.twoThirdsMajority, vs.twoThirdsCommitTime, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *VoteSet) MakePOL() *POL {
|
func (vs *VoteSet) MakePOL() *POL {
|
||||||
@ -169,7 +169,7 @@ func (vs *VoteSet) MakePOL() *POL {
|
|||||||
}
|
}
|
||||||
vs.mtx.Lock()
|
vs.mtx.Lock()
|
||||||
defer vs.mtx.Unlock()
|
defer vs.mtx.Unlock()
|
||||||
if vs.twoThirdsCommitTime.IsZero() {
|
if !vs.twoThirdsExists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
majHash := vs.twoThirdsMajority // hash may be nil.
|
majHash := vs.twoThirdsMajority // hash may be nil.
|
||||||
|
@ -20,8 +20,8 @@ func TestAddVote(t *testing.T) {
|
|||||||
if voteSet.BitArray().GetIndex(0) {
|
if voteSet.BitArray().GetIndex(0) {
|
||||||
t.Errorf("Expected BitArray.GetIndex(0) to be false")
|
t.Errorf("Expected BitArray.GetIndex(0) to be false")
|
||||||
}
|
}
|
||||||
hash, commitTime, ok := voteSet.TwoThirdsMajority()
|
hash, ok := voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || !commitTime.IsZero() || ok {
|
if hash != nil || ok {
|
||||||
t.Errorf("There should be no 2/3 majority")
|
t.Errorf("There should be no 2/3 majority")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +35,8 @@ func TestAddVote(t *testing.T) {
|
|||||||
if !voteSet.BitArray().GetIndex(0) {
|
if !voteSet.BitArray().GetIndex(0) {
|
||||||
t.Errorf("Expected BitArray.GetIndex(0) to be true")
|
t.Errorf("Expected BitArray.GetIndex(0) to be true")
|
||||||
}
|
}
|
||||||
hash, commitTime, ok = voteSet.TwoThirdsMajority()
|
hash, ok = voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || !commitTime.IsZero() || ok {
|
if hash != nil || ok {
|
||||||
t.Errorf("There should be no 2/3 majority")
|
t.Errorf("There should be no 2/3 majority")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,8 +50,8 @@ func Test2_3Majority(t *testing.T) {
|
|||||||
privAccounts[i].Sign(vote)
|
privAccounts[i].Sign(vote)
|
||||||
voteSet.Add(vote)
|
voteSet.Add(vote)
|
||||||
}
|
}
|
||||||
hash, commitTime, ok := voteSet.TwoThirdsMajority()
|
hash, ok := voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || !commitTime.IsZero() || ok {
|
if hash != nil || ok {
|
||||||
t.Errorf("There should be no 2/3 majority")
|
t.Errorf("There should be no 2/3 majority")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ func Test2_3Majority(t *testing.T) {
|
|||||||
vote.BlockHash = CRandBytes(32)
|
vote.BlockHash = CRandBytes(32)
|
||||||
privAccounts[6].Sign(vote)
|
privAccounts[6].Sign(vote)
|
||||||
voteSet.Add(vote)
|
voteSet.Add(vote)
|
||||||
hash, commitTime, ok = voteSet.TwoThirdsMajority()
|
hash, ok = voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || !commitTime.IsZero() || ok {
|
if hash != nil || ok {
|
||||||
t.Errorf("There should be no 2/3 majority")
|
t.Errorf("There should be no 2/3 majority")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +68,8 @@ func Test2_3Majority(t *testing.T) {
|
|||||||
vote.BlockHash = nil
|
vote.BlockHash = nil
|
||||||
privAccounts[7].Sign(vote)
|
privAccounts[7].Sign(vote)
|
||||||
voteSet.Add(vote)
|
voteSet.Add(vote)
|
||||||
hash, commitTime, ok = voteSet.TwoThirdsMajority()
|
hash, ok = voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || commitTime.IsZero() || !ok {
|
if hash != nil || !ok {
|
||||||
t.Errorf("There should be 2/3 majority for nil")
|
t.Errorf("There should be 2/3 majority for nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +128,8 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
|
|||||||
privAccounts[i].Sign(vote)
|
privAccounts[i].Sign(vote)
|
||||||
voteSet.Add(vote)
|
voteSet.Add(vote)
|
||||||
}
|
}
|
||||||
hash, commitTime, ok := voteSet.TwoThirdsMajority()
|
hash, ok := voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || !commitTime.IsZero() || ok {
|
if hash != nil || ok {
|
||||||
t.Errorf("There should be no 2/3 majority")
|
t.Errorf("There should be no 2/3 majority")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +174,8 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We should have 2/3 majority
|
// We should have 2/3 majority
|
||||||
hash, commitTime, ok = voteSet.TwoThirdsMajority()
|
hash, ok = voteSet.TwoThirdsMajority()
|
||||||
if hash != nil || commitTime.IsZero() || !ok {
|
if hash != nil || !ok {
|
||||||
t.Errorf("There should be 2/3 majority for nil")
|
t.Errorf("There should be 2/3 majority for nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user