github.com/okex/exchain@v1.8.0/libs/tendermint/types/proposal.go (about)

     1  package types
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/okex/exchain/libs/tendermint/libs/bytes"
     9  	tmproto "github.com/okex/exchain/libs/tendermint/proto/types"
    10  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    11  )
    12  
    13  var (
    14  	ErrInvalidBlockPartSignature = errors.New("error invalid block part signature")
    15  	ErrInvalidBlockPartHash      = errors.New("error invalid block part hash")
    16  )
    17  
    18  // Proposal defines a block proposal for the consensus.
    19  // It refers to the block by BlockID field.
    20  // It must be signed by the correct proposer for the given Height/Round
    21  // to be considered valid. It may depend on votes from a previous round,
    22  // a so-called Proof-of-Lock (POL) round, as noted in the POLRound.
    23  // If POLRound >= 0, then BlockID corresponds to the block that is locked in POLRound.
    24  type Proposal struct {
    25  	Type      SignedMsgType
    26  	Height    int64     `json:"height"`
    27  	Round     int       `json:"round"`
    28  	POLRound  int       `json:"pol_round"` // -1 if null.
    29  	BlockID   BlockID   `json:"block_id"`
    30  	Timestamp time.Time `json:"timestamp"`
    31  	Signature []byte    `json:"signature"`
    32  	HasVC     bool      `json:"has_vc"` // enterNewRoundAVC at this Height
    33  }
    34  
    35  // NewProposal returns a new Proposal.
    36  // If there is no POLRound, polRound should be -1.
    37  func NewProposal(height int64, round int, polRound int, blockID BlockID) *Proposal {
    38  	return &Proposal{
    39  		Type:      ProposalType,
    40  		Height:    height,
    41  		Round:     round,
    42  		BlockID:   blockID,
    43  		POLRound:  polRound,
    44  		Timestamp: tmtime.Now(),
    45  	}
    46  }
    47  
    48  // ValidateBasic performs basic validation.
    49  func (p *Proposal) ValidateBasic() error {
    50  	if p.Type != ProposalType {
    51  		return errors.New("invalid Type")
    52  	}
    53  	if p.Height < 0 {
    54  		return errors.New("negative Height")
    55  	}
    56  	if p.Round < 0 {
    57  		return errors.New("negative Round")
    58  	}
    59  	if p.POLRound < -1 {
    60  		return errors.New("negative POLRound (exception: -1)")
    61  	}
    62  	if err := p.BlockID.ValidateBasic(); err != nil {
    63  		return fmt.Errorf("wrong BlockID: %v", err)
    64  	}
    65  	// ValidateBasic above would pass even if the BlockID was empty:
    66  	if !p.BlockID.IsComplete() {
    67  		return fmt.Errorf("expected a complete, non-empty BlockID, got: %v", p.BlockID)
    68  	}
    69  
    70  	// NOTE: Timestamp validation is subtle and handled elsewhere.
    71  
    72  	if len(p.Signature) == 0 {
    73  		return errors.New("signature is missing")
    74  	}
    75  	if len(p.Signature) > MaxSignatureSize {
    76  		return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
    77  	}
    78  	return nil
    79  }
    80  
    81  // String returns a string representation of the Proposal.
    82  func (p *Proposal) String() string {
    83  	return fmt.Sprintf("Proposal{%v/%v (%v, %v) %X @ %s}",
    84  		p.Height,
    85  		p.Round,
    86  		p.BlockID,
    87  		p.POLRound,
    88  		bytes.Fingerprint(p.Signature),
    89  		CanonicalTime(p.Timestamp))
    90  }
    91  
    92  // SignBytes returns the Proposal bytes for signing
    93  func (p *Proposal) SignBytes(chainID string) []byte {
    94  	bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeProposal(chainID, p))
    95  	if err != nil {
    96  		panic(err)
    97  	}
    98  	return bz
    99  }
   100  
   101  // ToProto converts Proposal to protobuf
   102  func (p *Proposal) ToProto() *tmproto.Proposal {
   103  	if p == nil {
   104  		return nil
   105  	}
   106  	pb := new(tmproto.Proposal)
   107  
   108  	pb.BlockID = p.BlockID.ToProto()
   109  	pb.Type = tmproto.SignedMsgType(p.Type)
   110  	pb.Height = p.Height
   111  	pb.Round = int32(p.Round)
   112  	pb.PolRound = int32(p.POLRound)
   113  	pb.Timestamp = p.Timestamp
   114  	pb.Signature = p.Signature
   115  
   116  	return pb
   117  }
   118  
   119  // FromProto sets a protobuf Proposal to the given pointer.
   120  // It returns an error if the proposal is invalid.
   121  func ProposalFromProto(pp *tmproto.Proposal) (*Proposal, error) {
   122  	if pp == nil {
   123  		return nil, errors.New("nil proposal")
   124  	}
   125  
   126  	p := new(Proposal)
   127  
   128  	blockID, err := BlockIDFromProto(&pp.BlockID)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	p.BlockID = *blockID
   134  	p.Type = SignedMsgType(pp.Type)
   135  	p.Height = pp.Height
   136  	p.Round = int(pp.Round)
   137  	p.POLRound = int(pp.PolRound)
   138  	p.Timestamp = pp.Timestamp
   139  	p.Signature = pp.Signature
   140  
   141  	return p, p.ValidateBasic()
   142  }