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 }