github.com/Finschia/ostracon@v1.1.5/consensus/msgs.go (about)

     1  package consensus
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/gogo/protobuf/proto"
     8  	tmcons "github.com/tendermint/tendermint/proto/tendermint/consensus"
     9  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    10  
    11  	cstypes "github.com/Finschia/ostracon/consensus/types"
    12  	"github.com/Finschia/ostracon/libs/bits"
    13  	tmmath "github.com/Finschia/ostracon/libs/math"
    14  	"github.com/Finschia/ostracon/p2p"
    15  	"github.com/Finschia/ostracon/types"
    16  )
    17  
    18  // MsgToProto takes a consensus message type and returns the proto defined consensus message.
    19  //
    20  // TODO: This needs to be removed, but WALToProto depends on this.
    21  func MsgToProto(msg Message) (*tmcons.Message, error) {
    22  	if msg == nil {
    23  		return nil, errors.New("consensus: message is nil")
    24  	}
    25  	switch msg := msg.(type) {
    26  	case *NewRoundStepMessage:
    27  		m := &tmcons.NewRoundStep{
    28  			Height:                msg.Height,
    29  			Round:                 msg.Round,
    30  			Step:                  uint32(msg.Step),
    31  			SecondsSinceStartTime: msg.SecondsSinceStartTime,
    32  			LastCommitRound:       msg.LastCommitRound,
    33  		}
    34  		return m.Wrap().(*tmcons.Message), nil
    35  
    36  	case *NewValidBlockMessage:
    37  		pbPartSetHeader := msg.BlockPartSetHeader.ToProto()
    38  		pbBits := msg.BlockParts.ToProto()
    39  		m := &tmcons.NewValidBlock{
    40  			Height:             msg.Height,
    41  			Round:              msg.Round,
    42  			BlockPartSetHeader: pbPartSetHeader,
    43  			BlockParts:         pbBits,
    44  			IsCommit:           msg.IsCommit,
    45  		}
    46  		return m.Wrap().(*tmcons.Message), nil
    47  
    48  	case *ProposalMessage:
    49  		pbP := msg.Proposal.ToProto()
    50  		m := &tmcons.Proposal{
    51  			Proposal: *pbP,
    52  		}
    53  		return m.Wrap().(*tmcons.Message), nil
    54  
    55  	case *ProposalPOLMessage:
    56  		pbBits := msg.ProposalPOL.ToProto()
    57  		m := &tmcons.ProposalPOL{
    58  			Height:           msg.Height,
    59  			ProposalPolRound: msg.ProposalPOLRound,
    60  			ProposalPol:      *pbBits,
    61  		}
    62  		return m.Wrap().(*tmcons.Message), nil
    63  
    64  	case *BlockPartMessage:
    65  		parts, err := msg.Part.ToProto()
    66  		if err != nil {
    67  			return nil, fmt.Errorf("msg to proto error: %w", err)
    68  		}
    69  		m := &tmcons.BlockPart{
    70  			Height: msg.Height,
    71  			Round:  msg.Round,
    72  			Part:   *parts,
    73  		}
    74  		return m.Wrap().(*tmcons.Message), nil
    75  
    76  	case *VoteMessage:
    77  		vote := msg.Vote.ToProto()
    78  		m := &tmcons.Vote{
    79  			Vote: vote,
    80  		}
    81  		return m.Wrap().(*tmcons.Message), nil
    82  
    83  	case *HasVoteMessage:
    84  		m := &tmcons.HasVote{
    85  			Height: msg.Height,
    86  			Round:  msg.Round,
    87  			Type:   msg.Type,
    88  			Index:  msg.Index,
    89  		}
    90  		return m.Wrap().(*tmcons.Message), nil
    91  
    92  	case *VoteSetMaj23Message:
    93  		bi := msg.BlockID.ToProto()
    94  		m := &tmcons.VoteSetMaj23{
    95  			Height:  msg.Height,
    96  			Round:   msg.Round,
    97  			Type:    msg.Type,
    98  			BlockID: bi,
    99  		}
   100  		return m.Wrap().(*tmcons.Message), nil
   101  
   102  	case *VoteSetBitsMessage:
   103  		bi := msg.BlockID.ToProto()
   104  		bits := msg.Votes.ToProto()
   105  
   106  		m := &tmcons.VoteSetBits{
   107  			Height:  msg.Height,
   108  			Round:   msg.Round,
   109  			Type:    msg.Type,
   110  			BlockID: bi,
   111  		}
   112  
   113  		if bits != nil {
   114  			m.Votes = *bits
   115  		}
   116  
   117  		return m.Wrap().(*tmcons.Message), nil
   118  
   119  	default:
   120  		return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
   121  	}
   122  }
   123  
   124  // MsgFromProto takes a consensus proto message and returns the native go type
   125  func MsgFromProto(p *tmcons.Message) (Message, error) {
   126  	if p == nil {
   127  		return nil, errors.New("consensus: nil message")
   128  	}
   129  	var pb Message
   130  	um, err := p.Unwrap()
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	switch msg := um.(type) {
   136  	case *tmcons.NewRoundStep:
   137  		rs, err := tmmath.SafeConvertUint8(int64(msg.Step))
   138  		// deny message based on possible overflow
   139  		if err != nil {
   140  			return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
   141  		}
   142  		pb = &NewRoundStepMessage{
   143  			Height:                msg.Height,
   144  			Round:                 msg.Round,
   145  			Step:                  cstypes.RoundStepType(rs),
   146  			SecondsSinceStartTime: msg.SecondsSinceStartTime,
   147  			LastCommitRound:       msg.LastCommitRound,
   148  		}
   149  	case *tmcons.NewValidBlock:
   150  		pbPartSetHeader, err := types.PartSetHeaderFromProto(&msg.BlockPartSetHeader)
   151  		if err != nil {
   152  			return nil, fmt.Errorf("parts to proto error: %w", err)
   153  		}
   154  
   155  		pbBits := new(bits.BitArray)
   156  		pbBits.FromProto(msg.BlockParts)
   157  
   158  		pb = &NewValidBlockMessage{
   159  			Height:             msg.Height,
   160  			Round:              msg.Round,
   161  			BlockPartSetHeader: *pbPartSetHeader,
   162  			BlockParts:         pbBits,
   163  			IsCommit:           msg.IsCommit,
   164  		}
   165  	case *tmcons.Proposal:
   166  		pbP, err := types.ProposalFromProto(&msg.Proposal)
   167  		if err != nil {
   168  			return nil, fmt.Errorf("proposal msg to proto error: %w", err)
   169  		}
   170  
   171  		pb = &ProposalMessage{
   172  			Proposal: pbP,
   173  		}
   174  	case *tmcons.ProposalPOL:
   175  		pbBits := new(bits.BitArray)
   176  		pbBits.FromProto(&msg.ProposalPol)
   177  		pb = &ProposalPOLMessage{
   178  			Height:           msg.Height,
   179  			ProposalPOLRound: msg.ProposalPolRound,
   180  			ProposalPOL:      pbBits,
   181  		}
   182  	case *tmcons.BlockPart:
   183  		parts, err := types.PartFromProto(&msg.Part)
   184  		if err != nil {
   185  			return nil, fmt.Errorf("blockpart msg to proto error: %w", err)
   186  		}
   187  		pb = &BlockPartMessage{
   188  			Height: msg.Height,
   189  			Round:  msg.Round,
   190  			Part:   parts,
   191  		}
   192  	case *tmcons.Vote:
   193  		vote, err := types.VoteFromProto(msg.Vote)
   194  		if err != nil {
   195  			return nil, fmt.Errorf("vote msg to proto error: %w", err)
   196  		}
   197  
   198  		pb = &VoteMessage{
   199  			Vote: vote,
   200  		}
   201  	case *tmcons.HasVote:
   202  		pb = &HasVoteMessage{
   203  			Height: msg.Height,
   204  			Round:  msg.Round,
   205  			Type:   msg.Type,
   206  			Index:  msg.Index,
   207  		}
   208  	case *tmcons.VoteSetMaj23:
   209  		bi, err := types.BlockIDFromProto(&msg.BlockID)
   210  		if err != nil {
   211  			return nil, fmt.Errorf("voteSetMaj23 msg to proto error: %w", err)
   212  		}
   213  		pb = &VoteSetMaj23Message{
   214  			Height:  msg.Height,
   215  			Round:   msg.Round,
   216  			Type:    msg.Type,
   217  			BlockID: *bi,
   218  		}
   219  	case *tmcons.VoteSetBits:
   220  		bi, err := types.BlockIDFromProto(&msg.BlockID)
   221  		if err != nil {
   222  			return nil, fmt.Errorf("voteSetBits msg to proto error: %w", err)
   223  		}
   224  		bits := new(bits.BitArray)
   225  		bits.FromProto(&msg.Votes)
   226  
   227  		pb = &VoteSetBitsMessage{
   228  			Height:  msg.Height,
   229  			Round:   msg.Round,
   230  			Type:    msg.Type,
   231  			BlockID: *bi,
   232  			Votes:   bits,
   233  		}
   234  	default:
   235  		return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
   236  	}
   237  
   238  	if err := pb.ValidateBasic(); err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	return pb, nil
   243  }
   244  
   245  // MustEncode takes the reactors msg, makes it proto and marshals it
   246  // this mimics `MustMarshalBinaryBare` in that is panics on error
   247  //
   248  // Deprecated: Will be removed in v0.37.
   249  func MustEncode(msg Message) []byte {
   250  	pb, err := MsgToProto(msg)
   251  	if err != nil {
   252  		panic(err)
   253  	}
   254  	enc, err := proto.Marshal(pb)
   255  	if err != nil {
   256  		panic(err)
   257  	}
   258  	return enc
   259  }
   260  
   261  // WALToProto takes a WAL message and return a proto walMessage and error
   262  func WALToProto(msg WALMessage) (*tmcons.WALMessage, error) {
   263  	var pb tmcons.WALMessage
   264  
   265  	switch msg := msg.(type) {
   266  	case types.EventDataRoundState:
   267  		pb = tmcons.WALMessage{
   268  			Sum: &tmcons.WALMessage_EventDataRoundState{
   269  				EventDataRoundState: &tmproto.EventDataRoundState{
   270  					Height: msg.Height,
   271  					Round:  msg.Round,
   272  					Step:   msg.Step,
   273  				},
   274  			},
   275  		}
   276  	case msgInfo:
   277  		consMsg, err := MsgToProto(msg.Msg)
   278  		if err != nil {
   279  			return nil, err
   280  		}
   281  		pb = tmcons.WALMessage{
   282  			Sum: &tmcons.WALMessage_MsgInfo{
   283  				MsgInfo: &tmcons.MsgInfo{
   284  					Msg:    *consMsg,
   285  					PeerID: string(msg.PeerID),
   286  				},
   287  			},
   288  		}
   289  	case timeoutInfo:
   290  		pb = tmcons.WALMessage{
   291  			Sum: &tmcons.WALMessage_TimeoutInfo{
   292  				TimeoutInfo: &tmcons.TimeoutInfo{
   293  					Duration: msg.Duration,
   294  					Height:   msg.Height,
   295  					Round:    msg.Round,
   296  					Step:     uint32(msg.Step),
   297  				},
   298  			},
   299  		}
   300  	case EndHeightMessage:
   301  		pb = tmcons.WALMessage{
   302  			Sum: &tmcons.WALMessage_EndHeight{
   303  				EndHeight: &tmcons.EndHeight{
   304  					Height: msg.Height,
   305  				},
   306  			},
   307  		}
   308  	default:
   309  		return nil, fmt.Errorf("to proto: wal message not recognized: %T", msg)
   310  	}
   311  
   312  	return &pb, nil
   313  }
   314  
   315  // WALFromProto takes a proto wal message and return a consensus walMessage and error
   316  func WALFromProto(msg *tmcons.WALMessage) (WALMessage, error) {
   317  	if msg == nil {
   318  		return nil, errors.New("nil WAL message")
   319  	}
   320  	var pb WALMessage
   321  
   322  	switch msg := msg.Sum.(type) {
   323  	case *tmcons.WALMessage_EventDataRoundState:
   324  		pb = types.EventDataRoundState{
   325  			Height: msg.EventDataRoundState.Height,
   326  			Round:  msg.EventDataRoundState.Round,
   327  			Step:   msg.EventDataRoundState.Step,
   328  		}
   329  	case *tmcons.WALMessage_MsgInfo:
   330  		walMsg, err := MsgFromProto(&msg.MsgInfo.Msg)
   331  		if err != nil {
   332  			return nil, fmt.Errorf("msgInfo from proto error: %w", err)
   333  		}
   334  		pb = msgInfo{
   335  			Msg:    walMsg,
   336  			PeerID: p2p.ID(msg.MsgInfo.PeerID),
   337  		}
   338  
   339  	case *tmcons.WALMessage_TimeoutInfo:
   340  		tis, err := tmmath.SafeConvertUint8(int64(msg.TimeoutInfo.Step))
   341  		// deny message based on possible overflow
   342  		if err != nil {
   343  			return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
   344  		}
   345  		pb = timeoutInfo{
   346  			Duration: msg.TimeoutInfo.Duration,
   347  			Height:   msg.TimeoutInfo.Height,
   348  			Round:    msg.TimeoutInfo.Round,
   349  			Step:     cstypes.RoundStepType(tis),
   350  		}
   351  		return pb, nil
   352  	case *tmcons.WALMessage_EndHeight:
   353  		pb := EndHeightMessage{
   354  			Height: msg.EndHeight.Height,
   355  		}
   356  		return pb, nil
   357  	default:
   358  		return nil, fmt.Errorf("from proto: wal message not recognized: %T", msg)
   359  	}
   360  	return pb, nil
   361  }