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  }