You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
7.9 KiB

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