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  }