github.com/evdatsion/aphelion-dpos-bft@v0.32.1/types/vote.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/evdatsion/aphelion-dpos-bft/crypto" 10 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 11 ) 12 13 const ( 14 // MaxVoteBytes is a maximum vote size (including amino overhead). 15 MaxVoteBytes int64 = 223 16 ) 17 18 var ( 19 ErrVoteUnexpectedStep = errors.New("Unexpected step") 20 ErrVoteInvalidValidatorIndex = errors.New("Invalid validator index") 21 ErrVoteInvalidValidatorAddress = errors.New("Invalid validator address") 22 ErrVoteInvalidSignature = errors.New("Invalid signature") 23 ErrVoteInvalidBlockHash = errors.New("Invalid block hash") 24 ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature") 25 ErrVoteNil = errors.New("Nil vote") 26 ) 27 28 type ErrVoteConflictingVotes struct { 29 *DuplicateVoteEvidence 30 } 31 32 func (err *ErrVoteConflictingVotes) Error() string { 33 return fmt.Sprintf("Conflicting votes from validator %v", err.PubKey.Address()) 34 } 35 36 func NewConflictingVoteError(val *Validator, voteA, voteB *Vote) *ErrVoteConflictingVotes { 37 return &ErrVoteConflictingVotes{ 38 &DuplicateVoteEvidence{ 39 PubKey: val.PubKey, 40 VoteA: voteA, 41 VoteB: voteB, 42 }, 43 } 44 } 45 46 // Address is hex bytes. 47 type Address = crypto.Address 48 49 // Vote represents a prevote, precommit, or commit vote from validators for 50 // consensus. 51 type Vote struct { 52 Type SignedMsgType `json:"type"` 53 Height int64 `json:"height"` 54 Round int `json:"round"` 55 BlockID BlockID `json:"block_id"` // zero if vote is nil. 56 Timestamp time.Time `json:"timestamp"` 57 ValidatorAddress Address `json:"validator_address"` 58 ValidatorIndex int `json:"validator_index"` 59 Signature []byte `json:"signature"` 60 } 61 62 // CommitSig converts the Vote to a CommitSig. 63 // If the Vote is nil, the CommitSig will be nil. 64 func (vote *Vote) CommitSig() *CommitSig { 65 if vote == nil { 66 return nil 67 } 68 cs := CommitSig(*vote) 69 return &cs 70 } 71 72 func (vote *Vote) SignBytes(chainID string) []byte { 73 bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote)) 74 if err != nil { 75 panic(err) 76 } 77 return bz 78 } 79 80 func (vote *Vote) Copy() *Vote { 81 voteCopy := *vote 82 return &voteCopy 83 } 84 85 func (vote *Vote) String() string { 86 if vote == nil { 87 return "nil-Vote" 88 } 89 var typeString string 90 switch vote.Type { 91 case PrevoteType: 92 typeString = "Prevote" 93 case PrecommitType: 94 typeString = "Precommit" 95 default: 96 panic("Unknown vote type") 97 } 98 99 return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}", 100 vote.ValidatorIndex, 101 cmn.Fingerprint(vote.ValidatorAddress), 102 vote.Height, 103 vote.Round, 104 vote.Type, 105 typeString, 106 cmn.Fingerprint(vote.BlockID.Hash), 107 cmn.Fingerprint(vote.Signature), 108 CanonicalTime(vote.Timestamp), 109 ) 110 } 111 112 func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { 113 if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) { 114 return ErrVoteInvalidValidatorAddress 115 } 116 117 if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) { 118 return ErrVoteInvalidSignature 119 } 120 return nil 121 } 122 123 // ValidateBasic performs basic validation. 124 func (vote *Vote) ValidateBasic() error { 125 if !IsVoteTypeValid(vote.Type) { 126 return errors.New("Invalid Type") 127 } 128 if vote.Height < 0 { 129 return errors.New("Negative Height") 130 } 131 if vote.Round < 0 { 132 return errors.New("Negative Round") 133 } 134 135 // NOTE: Timestamp validation is subtle and handled elsewhere. 136 137 if err := vote.BlockID.ValidateBasic(); err != nil { 138 return fmt.Errorf("Wrong BlockID: %v", err) 139 } 140 // BlockID.ValidateBasic would not err if we for instance have an empty hash but a 141 // non-empty PartsSetHeader: 142 if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() { 143 return fmt.Errorf("BlockID must be either empty or complete, got: %v", vote.BlockID) 144 } 145 if len(vote.ValidatorAddress) != crypto.AddressSize { 146 return fmt.Errorf("Expected ValidatorAddress size to be %d bytes, got %d bytes", 147 crypto.AddressSize, 148 len(vote.ValidatorAddress), 149 ) 150 } 151 if vote.ValidatorIndex < 0 { 152 return errors.New("Negative ValidatorIndex") 153 } 154 if len(vote.Signature) == 0 { 155 return errors.New("Signature is missing") 156 } 157 if len(vote.Signature) > MaxSignatureSize { 158 return fmt.Errorf("Signature is too big (max: %d)", MaxSignatureSize) 159 } 160 return nil 161 }