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 }