github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/consensus/consensus_precommit.go (about)

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