github.com/badrootd/nibiru-cometbft@v0.37.5-0.20240307173500-2a75559eee9b/consensus/msgs.go (about)

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