github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/consensus/types/round_state.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 "github.com/line/ostracon/libs/bytes" 9 "github.com/line/ostracon/types" 10 ) 11 12 //----------------------------------------------------------------------------- 13 // RoundStepType enum type 14 15 // RoundStepType enumerates the state of the consensus state machine 16 type RoundStepType uint8 // These must be numeric, ordered. 17 18 // RoundStepType 19 const ( 20 RoundStepNewHeight = RoundStepType(0x01) // Wait til CommitTime + timeoutCommit 21 RoundStepNewRound = RoundStepType(0x02) // Setup new round and go to RoundStepPropose 22 RoundStepPropose = RoundStepType(0x03) // Did propose, gossip proposal 23 RoundStepPrevote = RoundStepType(0x04) // Did prevote, gossip prevotes 24 RoundStepPrevoteWait = RoundStepType(0x05) // Did receive any +2/3 prevotes, start timeout 25 RoundStepPrecommit = RoundStepType(0x06) // Did precommit, gossip precommits 26 RoundStepPrecommitWait = RoundStepType(0x07) // Did receive any +2/3 precommits, start timeout 27 RoundStepCommit = RoundStepType(0x08) // Entered commit state machine 28 // NOTE: RoundStepNewHeight acts as RoundStepCommitWait. 29 30 // NOTE: Update IsValid method if you change this! 31 ) 32 33 // IsValid returns true if the step is valid, false if unknown/undefined. 34 func (rs RoundStepType) IsValid() bool { 35 return uint8(rs) >= 0x01 && uint8(rs) <= 0x08 36 } 37 38 // String returns a string 39 func (rs RoundStepType) String() string { 40 switch rs { 41 case RoundStepNewHeight: 42 return "RoundStepNewHeight" 43 case RoundStepNewRound: 44 return "RoundStepNewRound" 45 case RoundStepPropose: 46 return "RoundStepPropose" 47 case RoundStepPrevote: 48 return "RoundStepPrevote" 49 case RoundStepPrevoteWait: 50 return "RoundStepPrevoteWait" 51 case RoundStepPrecommit: 52 return "RoundStepPrecommit" 53 case RoundStepPrecommitWait: 54 return "RoundStepPrecommitWait" 55 case RoundStepCommit: 56 return "RoundStepCommit" 57 default: 58 return "RoundStepUnknown" // Cannot panic. 59 } 60 } 61 62 //----------------------------------------------------------------------------- 63 64 // RoundState defines the internal consensus state. 65 // NOTE: Not thread safe. Should only be manipulated by functions downstream 66 // of the cs.receiveRoutine 67 type RoundState struct { 68 Height int64 `json:"height"` // Height we are working on 69 Round int32 `json:"round"` 70 Step RoundStepType `json:"step"` 71 StartTime time.Time `json:"start_time"` 72 73 // Subjective time when +2/3 precommits for Block at Round were found 74 CommitTime time.Time `json:"commit_time"` 75 Validators *types.ValidatorSet `json:"validators"` 76 Proposer *types.Validator `json:"proposer"` 77 Proposal *types.Proposal `json:"proposal"` 78 ProposalBlock *types.Block `json:"proposal_block"` 79 ProposalBlockParts *types.PartSet `json:"proposal_block_parts"` 80 LockedRound int32 `json:"locked_round"` 81 LockedBlock *types.Block `json:"locked_block"` 82 LockedBlockParts *types.PartSet `json:"locked_block_parts"` 83 84 // Last known round with POL for non-nil valid block. 85 ValidRound int32 `json:"valid_round"` 86 ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above. 87 88 // Last known block parts of POL mentioned above. 89 ValidBlockParts *types.PartSet `json:"valid_block_parts"` 90 Votes *HeightVoteSet `json:"votes"` 91 CommitRound int32 `json:"commit_round"` // 92 LastCommit *types.VoteSet `json:"last_commit"` // Last precommits at Height-1 93 LastValidators *types.ValidatorSet `json:"last_validators"` 94 TriggeredTimeoutPrecommit bool `json:"triggered_timeout_precommit"` 95 } 96 97 // Compressed version of the RoundState for use in RPC 98 type RoundStateSimple struct { 99 HeightRoundStep string `json:"height/round/step"` 100 StartTime time.Time `json:"start_time"` 101 ProposalBlockHash bytes.HexBytes `json:"proposal_block_hash"` 102 LockedBlockHash bytes.HexBytes `json:"locked_block_hash"` 103 ValidBlockHash bytes.HexBytes `json:"valid_block_hash"` 104 Votes json.RawMessage `json:"height_vote_set"` 105 Proposer types.ValidatorInfo `json:"proposer"` 106 } 107 108 // Compress the RoundState to RoundStateSimple 109 func (rs *RoundState) RoundStateSimple() RoundStateSimple { 110 votesJSON, err := rs.Votes.MarshalJSON() 111 if err != nil { 112 panic(err) 113 } 114 115 addr := rs.Proposer.Address 116 idx, _ := rs.Validators.GetByAddress(addr) 117 118 return RoundStateSimple{ 119 HeightRoundStep: fmt.Sprintf("%d/%d/%d", rs.Height, rs.Round, rs.Step), 120 StartTime: rs.StartTime, 121 ProposalBlockHash: rs.ProposalBlock.Hash(), 122 LockedBlockHash: rs.LockedBlock.Hash(), 123 ValidBlockHash: rs.ValidBlock.Hash(), 124 Votes: votesJSON, 125 Proposer: types.ValidatorInfo{ 126 Address: addr, 127 Index: idx, 128 }, 129 } 130 } 131 132 // NewRoundEvent returns the RoundState with proposer information as an event. 133 func (rs *RoundState) NewRoundEvent() types.EventDataNewRound { 134 addr := rs.Proposer.Address 135 idx, _ := rs.Validators.GetByAddress(addr) 136 137 return types.EventDataNewRound{ 138 Height: rs.Height, 139 Round: rs.Round, 140 Step: rs.Step.String(), 141 Proposer: types.ValidatorInfo{ 142 Address: addr, 143 Index: idx, 144 }, 145 } 146 } 147 148 // CompleteProposalEvent returns information about a proposed block as an event. 149 func (rs *RoundState) CompleteProposalEvent() types.EventDataCompleteProposal { 150 // We must construct BlockID from ProposalBlock and ProposalBlockParts 151 // cs.Proposal is not guaranteed to be set when this function is called 152 blockID := types.BlockID{ 153 Hash: rs.ProposalBlock.Hash(), 154 PartSetHeader: rs.ProposalBlockParts.Header(), 155 } 156 157 return types.EventDataCompleteProposal{ 158 Height: rs.Height, 159 Round: rs.Round, 160 Step: rs.Step.String(), 161 BlockID: blockID, 162 } 163 } 164 165 // RoundStateEvent returns the H/R/S of the RoundState as an event. 166 func (rs *RoundState) RoundStateEvent() types.EventDataRoundState { 167 return types.EventDataRoundState{ 168 Height: rs.Height, 169 Round: rs.Round, 170 Step: rs.Step.String(), 171 } 172 } 173 174 // String returns a string 175 func (rs *RoundState) String() string { 176 return rs.StringIndented("") 177 } 178 179 // StringIndented returns a string 180 func (rs *RoundState) StringIndented(indent string) string { 181 return fmt.Sprintf(`RoundState{ 182 %s H:%v R:%v S:%v 183 %s StartTime: %v 184 %s CommitTime: %v 185 %s Validators: %v 186 %s Proposer: %v 187 %s Proposal: %v 188 %s ProposalBlock: %v %v 189 %s LockedRound: %v 190 %s LockedBlock: %v %v 191 %s ValidRound: %v 192 %s ValidBlock: %v %v 193 %s Votes: %v 194 %s LastCommit: %v 195 %s LastValidators:%v 196 %s}`, 197 indent, rs.Height, rs.Round, rs.Step, 198 indent, rs.StartTime, 199 indent, rs.CommitTime, 200 indent, rs.Validators.StringIndented(indent+" "), 201 indent, rs.Proposer.String(), 202 indent, rs.Proposal, 203 indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(), 204 indent, rs.LockedRound, 205 indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(), 206 indent, rs.ValidRound, 207 indent, rs.ValidBlockParts.StringShort(), rs.ValidBlock.StringShort(), 208 indent, rs.Votes.StringIndented(indent+" "), 209 indent, rs.LastCommit.StringShort(), 210 indent, rs.LastValidators.StringIndented(indent+" "), 211 indent) 212 } 213 214 // StringShort returns a string 215 func (rs *RoundState) StringShort() string { 216 return fmt.Sprintf(`RoundState{H:%v R:%v S:%v ST:%v}`, 217 rs.Height, rs.Round, rs.Step, rs.StartTime) 218 }