You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.8 KiB

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