github.com/okex/exchain@v1.8.0/libs/tendermint/consensus/consensus_precommit.go (about)

     1  package consensus
     2  
     3  import (
     4  	"fmt"
     5  	cstypes "github.com/okex/exchain/libs/tendermint/consensus/types"
     6  	"github.com/okex/exchain/libs/tendermint/libs/automation"
     7  	"github.com/okex/exchain/libs/tendermint/types"
     8  )
     9  
    10  // Enter: `timeoutPrevote` after any +2/3 prevotes.
    11  // Enter: `timeoutPrecommit` after any +2/3 precommits.
    12  // Enter: +2/3 precomits for block or nil.
    13  // Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this round)
    14  // else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
    15  // else, precommit nil otherwise.
    16  func (cs *State) enterPrecommit(height int64, round int) {
    17  	logger := cs.Logger.With("height", height, "round", round)
    18  
    19  	if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) {
    20  		logger.Debug(fmt.Sprintf(
    21  			"enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v",
    22  			height,
    23  			round,
    24  			cs.Height,
    25  			cs.Round,
    26  			cs.Step))
    27  		return
    28  	}
    29  
    30  	cs.initNewHeight()
    31  	cs.trc.Pin("Precommit-%d", round)
    32  
    33  	logger.Info(fmt.Sprintf("enterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
    34  
    35  	defer func() {
    36  		// Done enterPrecommit:
    37  		cs.updateRoundStep(round, cstypes.RoundStepPrecommit)
    38  		cs.newStep()
    39  	}()
    40  
    41  	if automation.PrecommitNil(height, round) {
    42  		cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
    43  		return
    44  	}
    45  
    46  	// check for a polka
    47  	blockID, ok := cs.Votes.Prevotes(round).TwoThirdsMajority()
    48  
    49  	// If we don't have a polka, we must precommit nil.
    50  	if !ok {
    51  		if cs.LockedBlock != nil {
    52  			logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit while we're locked. Precommitting nil")
    53  		} else {
    54  			logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit. Precommitting nil.")
    55  		}
    56  		cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
    57  		return
    58  	}
    59  
    60  	// At this point +2/3 prevoted for a particular block or nil.
    61  	cs.eventBus.PublishEventPolka(cs.RoundStateEvent())
    62  
    63  	// the latest POLRound should be this round.
    64  	polRound, _ := cs.Votes.POLInfo()
    65  	if polRound < round {
    66  		panic(fmt.Sprintf("This POLRound should be %v but got %v", round, polRound))
    67  	}
    68  
    69  	// +2/3 prevoted nil. Unlock and precommit nil.
    70  	if len(blockID.Hash) == 0 {
    71  		if cs.LockedBlock == nil {
    72  			logger.Info("enterPrecommit: +2/3 prevoted for nil.")
    73  		} else {
    74  			logger.Info("enterPrecommit: +2/3 prevoted for nil. Unlocking")
    75  			cs.LockedRound = -1
    76  			cs.LockedBlock = nil
    77  			cs.LockedBlockParts = nil
    78  			cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
    79  		}
    80  		cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
    81  		return
    82  	}
    83  
    84  	// At this point, +2/3 prevoted for a particular block.
    85  
    86  	// If we're already locked on that block, precommit it, and update the LockedRound
    87  	if cs.LockedBlock.HashesTo(blockID.Hash) {
    88  		logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
    89  		cs.LockedRound = round
    90  		cs.eventBus.PublishEventRelock(cs.RoundStateEvent())
    91  		cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
    92  		return
    93  	}
    94  
    95  	// If +2/3 prevoted for proposal block, stage and precommit it
    96  	if cs.ProposalBlock.HashesTo(blockID.Hash) {
    97  		logger.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", blockID.Hash)
    98  		// Validate the block.
    99  		if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
   100  			panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
   101  		}
   102  		cs.LockedRound = round
   103  		cs.LockedBlock = cs.ProposalBlock
   104  		cs.LockedBlockParts = cs.ProposalBlockParts
   105  		cs.eventBus.PublishEventLock(cs.RoundStateEvent())
   106  		cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
   107  		return
   108  	}
   109  
   110  	// There was a polka in this round for a block we don't have.
   111  	// Fetch that block, unlock, and precommit nil.
   112  	// The +2/3 prevotes for this round is the POL for our unlock.
   113  	// TODO: In the future save the POL prevotes for justification.
   114  	cs.LockedRound = -1
   115  	cs.LockedBlock = nil
   116  	cs.LockedBlockParts = nil
   117  	if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
   118  		cs.ProposalBlock = nil
   119  		cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
   120  	}
   121  	cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
   122  	cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
   123  }
   124  
   125  // Enter: any +2/3 precommits for next round.
   126  func (cs *State) enterPrecommitWait(height int64, round int) {
   127  	logger := cs.Logger.With("height", height, "round", round)
   128  
   129  	if cs.Height != height || round < cs.Round || (cs.Round == round && cs.TriggeredTimeoutPrecommit) {
   130  		logger.Debug(
   131  			fmt.Sprintf(
   132  				"enterPrecommitWait(%v/%v): Invalid args. "+
   133  					"Current state is Height/Round: %v/%v/, TriggeredTimeoutPrecommit:%v",
   134  				height, round, cs.Height, cs.Round, cs.TriggeredTimeoutPrecommit))
   135  		return
   136  	}
   137  
   138  	cs.initNewHeight()
   139  	cs.trc.Pin("PrecommitWait-%d", round)
   140  
   141  	if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
   142  		panic(fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round))
   143  	}
   144  	logger.Info(fmt.Sprintf("enterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
   145  
   146  	defer func() {
   147  		// Done enterPrecommitWait:
   148  		cs.TriggeredTimeoutPrecommit = true
   149  		cs.newStep()
   150  	}()
   151  
   152  	// Wait for some more precommits; enterNewRound
   153  	cs.scheduleTimeout(cs.config.Precommit(round), height, round, cstypes.RoundStepPrecommitWait)
   154  
   155  }