github.com/evdatsion/aphelion-dpos-bft@v0.32.1/types/proposal.go (about)

     1  package types
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
     9  	tmtime "github.com/evdatsion/aphelion-dpos-bft/types/time"
    10  )
    11  
    12  var (
    13  	ErrInvalidBlockPartSignature = errors.New("Error invalid block part signature")
    14  	ErrInvalidBlockPartHash      = errors.New("Error invalid block part hash")
    15  )
    16  
    17  // Proposal defines a block proposal for the consensus.
    18  // It refers to the block by BlockID field.
    19  // It must be signed by the correct proposer for the given Height/Round
    20  // to be considered valid. It may depend on votes from a previous round,
    21  // a so-called Proof-of-Lock (POL) round, as noted in the POLRound.
    22  // If POLRound >= 0, then BlockID corresponds to the block that is locked in POLRound.
    23  type Proposal struct {
    24  	Type      SignedMsgType
    25  	Height    int64     `json:"height"`
    26  	Round     int       `json:"round"`
    27  	POLRound  int       `json:"pol_round"` // -1 if null.
    28  	BlockID   BlockID   `json:"block_id"`
    29  	Timestamp time.Time `json:"timestamp"`
    30  	Signature []byte    `json:"signature"`
    31  }
    32  
    33  // NewProposal returns a new Proposal.
    34  // If there is no POLRound, polRound should be -1.
    35  func NewProposal(height int64, round int, polRound int, blockID BlockID) *Proposal {
    36  	return &Proposal{
    37  		Type:      ProposalType,
    38  		Height:    height,
    39  		Round:     round,
    40  		BlockID:   blockID,
    41  		POLRound:  polRound,
    42  		Timestamp: tmtime.Now(),
    43  	}
    44  }
    45  
    46  // ValidateBasic performs basic validation.
    47  func (p *Proposal) ValidateBasic() error {
    48  	if p.Type != ProposalType {
    49  		return errors.New("Invalid Type")
    50  	}
    51  	if p.Height < 0 {
    52  		return errors.New("Negative Height")
    53  	}
    54  	if p.Round < 0 {
    55  		return errors.New("Negative Round")
    56  	}
    57  	if p.POLRound < -1 {
    58  		return errors.New("Negative POLRound (exception: -1)")
    59  	}
    60  	if err := p.BlockID.ValidateBasic(); err != nil {
    61  		return fmt.Errorf("Wrong BlockID: %v", err)
    62  	}
    63  	// ValidateBasic above would pass even if the BlockID was empty:
    64  	if !p.BlockID.IsComplete() {
    65  		return fmt.Errorf("Expected a complete, non-empty BlockID, got: %v", p.BlockID)
    66  	}
    67  
    68  	// NOTE: Timestamp validation is subtle and handled elsewhere.
    69  
    70  	if len(p.Signature) == 0 {
    71  		return errors.New("Signature is missing")
    72  	}
    73  	if len(p.Signature) > MaxSignatureSize {
    74  		return fmt.Errorf("Signature is too big (max: %d)", MaxSignatureSize)
    75  	}
    76  	return nil
    77  }
    78  
    79  // String returns a string representation of the Proposal.
    80  func (p *Proposal) String() string {
    81  	return fmt.Sprintf("Proposal{%v/%v (%v, %v) %X @ %s}",
    82  		p.Height,
    83  		p.Round,
    84  		p.BlockID,
    85  		p.POLRound,
    86  		cmn.Fingerprint(p.Signature),
    87  		CanonicalTime(p.Timestamp))
    88  }
    89  
    90  // SignBytes returns the Proposal bytes for signing
    91  func (p *Proposal) SignBytes(chainID string) []byte {
    92  	bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeProposal(chainID, p))
    93  	if err != nil {
    94  		panic(err)
    95  	}
    96  	return bz
    97  }