github.com/vipernet-xyz/tendermint-core@v0.32.0/types/vote.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/tendermint/tendermint/crypto" 10 tmbytes "github.com/tendermint/tendermint/libs/bytes" 11 tmproto "github.com/tendermint/tendermint/proto/types" 12 ) 13 14 const ( 15 // MaxVoteBytes is a maximum vote size (including amino overhead). 16 MaxVoteBytes int64 = 223 17 nilVoteStr string = "nil-Vote" 18 ) 19 20 var ( 21 ErrVoteUnexpectedStep = errors.New("unexpected step") 22 ErrVoteInvalidValidatorIndex = errors.New("invalid validator index") 23 ErrVoteInvalidValidatorAddress = errors.New("invalid validator address") 24 ErrVoteInvalidSignature = errors.New("invalid signature") 25 ErrVoteInvalidBlockHash = errors.New("invalid block hash") 26 ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature") 27 ErrVoteNil = errors.New("nil vote") 28 ) 29 30 type ErrVoteConflictingVotes struct { 31 *DuplicateVoteEvidence 32 } 33 34 func (err *ErrVoteConflictingVotes) Error() string { 35 return fmt.Sprintf("Conflicting votes from validator %v", err.PubKey.Address()) 36 } 37 38 func NewConflictingVoteError(val *Validator, vote1, vote2 *Vote) *ErrVoteConflictingVotes { 39 return &ErrVoteConflictingVotes{ 40 &DuplicateVoteEvidence{ 41 PubKey: val.PubKey, 42 VoteA: vote1, 43 VoteB: vote2, 44 }, 45 } 46 } 47 48 // Address is hex bytes. 49 type Address = crypto.Address 50 51 // Vote represents a prevote, precommit, or commit vote from validators for 52 // consensus. 53 type Vote struct { 54 Type SignedMsgType `json:"type"` 55 Height int64 `json:"height"` 56 Round int `json:"round"` 57 BlockID BlockID `json:"block_id"` // zero if vote is nil. 58 Timestamp time.Time `json:"timestamp"` 59 ValidatorAddress Address `json:"validator_address"` 60 ValidatorIndex int `json:"validator_index"` 61 Signature []byte `json:"signature"` 62 } 63 64 // CommitSig converts the Vote to a CommitSig. 65 // If the Vote is nil, the CommitSig will be nil. 66 func (vote *Vote) CommitSig() *CommitSig { 67 if vote == nil { 68 return nil 69 } 70 cs := CommitSig(*vote) 71 return &cs 72 } 73 74 func (vote *Vote) SignBytes(chainID string) []byte { 75 bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote)) 76 if err != nil { 77 panic(err) 78 } 79 return bz 80 } 81 82 func (vote *Vote) Copy() *Vote { 83 voteCopy := *vote 84 return &voteCopy 85 } 86 87 func (vote *Vote) String() string { 88 if vote == nil { 89 return nilVoteStr 90 } 91 92 var typeString string 93 switch vote.Type { 94 case PrevoteType: 95 typeString = "Prevote" 96 case PrecommitType: 97 typeString = "Precommit" 98 default: 99 panic("Unknown vote type") 100 } 101 102 return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}", 103 vote.ValidatorIndex, 104 tmbytes.Fingerprint(vote.ValidatorAddress), 105 vote.Height, 106 vote.Round, 107 vote.Type, 108 typeString, 109 tmbytes.Fingerprint(vote.BlockID.Hash), 110 tmbytes.Fingerprint(vote.Signature), 111 CanonicalTime(vote.Timestamp), 112 ) 113 } 114 115 func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { 116 if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) { 117 return ErrVoteInvalidValidatorAddress 118 } 119 120 if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) { 121 return ErrVoteInvalidSignature 122 } 123 return nil 124 } 125 126 // ValidateBasic performs basic validation. 127 func (vote *Vote) ValidateBasic() error { 128 if !IsVoteTypeValid(vote.Type) { 129 return errors.New("invalid Type") 130 } 131 if vote.Height < 0 { 132 return errors.New("negative Height") 133 } 134 if vote.Round < 0 { 135 return errors.New("negative Round") 136 } 137 138 // NOTE: Timestamp validation is subtle and handled elsewhere. 139 140 if err := vote.BlockID.ValidateBasic(); err != nil { 141 return fmt.Errorf("wrong BlockID: %v", err) 142 } 143 // BlockID.ValidateBasic would not err if we for instance have an empty hash but a 144 // non-empty PartsSetHeader: 145 if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() { 146 return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID) 147 } 148 if len(vote.ValidatorAddress) != crypto.AddressSize { 149 return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes", 150 crypto.AddressSize, 151 len(vote.ValidatorAddress), 152 ) 153 } 154 if vote.ValidatorIndex < 0 { 155 return errors.New("negative ValidatorIndex") 156 } 157 if len(vote.Signature) == 0 { 158 return errors.New("signature is missing") 159 } 160 if len(vote.Signature) > MaxSignatureSize { 161 return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize) 162 } 163 return nil 164 } 165 166 // ToProto converts the handwritten type to proto generated type 167 // return type, nil if everything converts safely, otherwise nil, error 168 func (vote *Vote) ToProto() *tmproto.Vote { 169 if vote == nil { 170 return nil 171 } 172 173 return &tmproto.Vote{ 174 Type: tmproto.SignedMsgType(vote.Type), 175 Height: vote.Height, 176 Round: int64(vote.Round), 177 BlockID: vote.BlockID.ToProto(), 178 Timestamp: vote.Timestamp, 179 ValidatorAddress: vote.ValidatorAddress, 180 ValidatorIndex: int64(vote.ValidatorIndex), 181 Signature: vote.Signature, 182 } 183 } 184 185 //FromProto converts a proto generetad type to a handwritten type 186 // return type, nil if everything converts safely, otherwise nil, error 187 func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { 188 if pv == nil { 189 return nil, errors.New("nil vote") 190 } 191 192 blockID, err := BlockIDFromProto(&pv.BlockID) 193 if err != nil { 194 return nil, err 195 } 196 197 vote := new(Vote) 198 vote.Type = SignedMsgType(pv.Type) 199 vote.Height = pv.Height 200 vote.Round = int(pv.Round) 201 vote.BlockID = *blockID 202 vote.Timestamp = pv.Timestamp 203 vote.ValidatorAddress = pv.ValidatorAddress 204 vote.ValidatorIndex = int(pv.ValidatorIndex) 205 vote.Signature = pv.Signature 206 207 return vote, vote.ValidateBasic() 208 }