github.com/evdatsion/aphelion-dpos-bft@v0.32.1/consensus/types/round_state.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 9 "github.com/evdatsion/aphelion-dpos-bft/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 int `json:"round"` 70 Step RoundStepType `json:"step"` 71 StartTime time.Time `json:"start_time"` 72 CommitTime time.Time `json:"commit_time"` // Subjective time when +2/3 precommits for Block at Round were found 73 Validators *types.ValidatorSet `json:"validators"` 74 Proposal *types.Proposal `json:"proposal"` 75 ProposalBlock *types.Block `json:"proposal_block"` 76 ProposalBlockParts *types.PartSet `json:"proposal_block_parts"` 77 LockedRound int `json:"locked_round"` 78 LockedBlock *types.Block `json:"locked_block"` 79 LockedBlockParts *types.PartSet `json:"locked_block_parts"` 80 ValidRound int `json:"valid_round"` // Last known round with POL for non-nil valid block. 81 ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above. 82 ValidBlockParts *types.PartSet `json:"valid_block_parts"` // Last known block parts of POL metnioned above. 83 Votes *HeightVoteSet `json:"votes"` 84 CommitRound int `json:"commit_round"` // 85 LastCommit *types.VoteSet `json:"last_commit"` // Last precommits at Height-1 86 LastValidators *types.ValidatorSet `json:"last_validators"` 87 TriggeredTimeoutPrecommit bool `json:"triggered_timeout_precommit"` 88 } 89 90 // Compressed version of the RoundState for use in RPC 91 type RoundStateSimple struct { 92 HeightRoundStep string `json:"height/round/step"` 93 StartTime time.Time `json:"start_time"` 94 ProposalBlockHash cmn.HexBytes `json:"proposal_block_hash"` 95 LockedBlockHash cmn.HexBytes `json:"locked_block_hash"` 96 ValidBlockHash cmn.HexBytes `json:"valid_block_hash"` 97 Votes json.RawMessage `json:"height_vote_set"` 98 } 99 100 // Compress the RoundState to RoundStateSimple 101 func (rs *RoundState) RoundStateSimple() RoundStateSimple { 102 votesJSON, err := rs.Votes.MarshalJSON() 103 if err != nil { 104 panic(err) 105 } 106 return RoundStateSimple{ 107 HeightRoundStep: fmt.Sprintf("%d/%d/%d", rs.Height, rs.Round, rs.Step), 108 StartTime: rs.StartTime, 109 ProposalBlockHash: rs.ProposalBlock.Hash(), 110 LockedBlockHash: rs.LockedBlock.Hash(), 111 ValidBlockHash: rs.ValidBlock.Hash(), 112 Votes: votesJSON, 113 } 114 } 115 116 // NewRoundEvent returns the RoundState with proposer information as an event. 117 func (rs *RoundState) NewRoundEvent() types.EventDataNewRound { 118 addr := rs.Validators.GetProposer().Address 119 idx, _ := rs.Validators.GetByAddress(addr) 120 121 return types.EventDataNewRound{ 122 Height: rs.Height, 123 Round: rs.Round, 124 Step: rs.Step.String(), 125 Proposer: types.ValidatorInfo{ 126 Address: addr, 127 Index: idx, 128 }, 129 } 130 } 131 132 // CompleteProposalEvent returns information about a proposed block as an event. 133 func (rs *RoundState) CompleteProposalEvent() types.EventDataCompleteProposal { 134 // We must construct BlockID from ProposalBlock and ProposalBlockParts 135 // cs.Proposal is not guaranteed to be set when this function is called 136 blockId := types.BlockID{ 137 Hash: rs.ProposalBlock.Hash(), 138 PartsHeader: rs.ProposalBlockParts.Header(), 139 } 140 141 return types.EventDataCompleteProposal{ 142 Height: rs.Height, 143 Round: rs.Round, 144 Step: rs.Step.String(), 145 BlockID: blockId, 146 } 147 } 148 149 // RoundStateEvent returns the H/R/S of the RoundState as an event. 150 func (rs *RoundState) RoundStateEvent() types.EventDataRoundState { 151 return types.EventDataRoundState{ 152 Height: rs.Height, 153 Round: rs.Round, 154 Step: rs.Step.String(), 155 } 156 } 157 158 // String returns a string 159 func (rs *RoundState) String() string { 160 return rs.StringIndented("") 161 } 162 163 // StringIndented returns a string 164 func (rs *RoundState) StringIndented(indent string) string { 165 return fmt.Sprintf(`RoundState{ 166 %s H:%v R:%v S:%v 167 %s StartTime: %v 168 %s CommitTime: %v 169 %s Validators: %v 170 %s Proposal: %v 171 %s ProposalBlock: %v %v 172 %s LockedRound: %v 173 %s LockedBlock: %v %v 174 %s ValidRound: %v 175 %s ValidBlock: %v %v 176 %s Votes: %v 177 %s LastCommit: %v 178 %s LastValidators:%v 179 %s}`, 180 indent, rs.Height, rs.Round, rs.Step, 181 indent, rs.StartTime, 182 indent, rs.CommitTime, 183 indent, rs.Validators.StringIndented(indent+" "), 184 indent, rs.Proposal, 185 indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(), 186 indent, rs.LockedRound, 187 indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(), 188 indent, rs.ValidRound, 189 indent, rs.ValidBlockParts.StringShort(), rs.ValidBlock.StringShort(), 190 indent, rs.Votes.StringIndented(indent+" "), 191 indent, rs.LastCommit.StringShort(), 192 indent, rs.LastValidators.StringIndented(indent+" "), 193 indent) 194 } 195 196 // StringShort returns a string 197 func (rs *RoundState) StringShort() string { 198 return fmt.Sprintf(`RoundState{H:%v R:%v S:%v ST:%v}`, 199 rs.Height, rs.Round, rs.Step, rs.StartTime) 200 } 201 202 //----------------------------------------------------------- 203 // These methods are for Protobuf Compatibility 204 205 // Size returns the size of the amino encoding, in bytes. 206 func (rs *RoundStateSimple) Size() int { 207 bs, _ := rs.Marshal() 208 return len(bs) 209 } 210 211 // Marshal returns the amino encoding. 212 func (rs *RoundStateSimple) Marshal() ([]byte, error) { 213 return cdc.MarshalBinaryBare(rs) 214 } 215 216 // MarshalTo calls Marshal and copies to the given buffer. 217 func (rs *RoundStateSimple) MarshalTo(data []byte) (int, error) { 218 bs, err := rs.Marshal() 219 if err != nil { 220 return -1, err 221 } 222 return copy(data, bs), nil 223 } 224 225 // Unmarshal deserializes from amino encoded form. 226 func (rs *RoundStateSimple) Unmarshal(bs []byte) error { 227 return cdc.UnmarshalBinaryBare(bs, rs) 228 }