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.

278 lines
7.6 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "time"
  7. "github.com/tendermint/tendermint/crypto"
  8. "github.com/tendermint/tendermint/internal/libs/protoio"
  9. tmbytes "github.com/tendermint/tendermint/libs/bytes"
  10. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  11. )
  12. const (
  13. nilVoteStr string = "nil-Vote"
  14. )
  15. var (
  16. ErrVoteUnexpectedStep = errors.New("unexpected step")
  17. ErrVoteInvalidValidatorIndex = errors.New("invalid validator index")
  18. ErrVoteInvalidValidatorAddress = errors.New("invalid validator address")
  19. ErrVoteInvalidSignature = errors.New("invalid signature")
  20. ErrVoteInvalidBlockHash = errors.New("invalid block hash")
  21. ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature")
  22. ErrVoteNil = errors.New("nil vote")
  23. ErrVoteInvalidExtension = errors.New("invalid vote extension")
  24. )
  25. type ErrVoteConflictingVotes struct {
  26. VoteA *Vote
  27. VoteB *Vote
  28. }
  29. func (err *ErrVoteConflictingVotes) Error() string {
  30. return fmt.Sprintf("conflicting votes from validator %X", err.VoteA.ValidatorAddress)
  31. }
  32. func NewConflictingVoteError(vote1, vote2 *Vote) *ErrVoteConflictingVotes {
  33. return &ErrVoteConflictingVotes{
  34. VoteA: vote1,
  35. VoteB: vote2,
  36. }
  37. }
  38. // Address is hex bytes.
  39. type Address = crypto.Address
  40. // Vote represents a prevote, precommit, or commit vote from validators for
  41. // consensus.
  42. type Vote struct {
  43. Type tmproto.SignedMsgType `json:"type"`
  44. Height int64 `json:"height,string"`
  45. Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds
  46. BlockID BlockID `json:"block_id"` // zero if vote is nil.
  47. Timestamp time.Time `json:"timestamp"`
  48. ValidatorAddress Address `json:"validator_address"`
  49. ValidatorIndex int32 `json:"validator_index"`
  50. Signature []byte `json:"signature"`
  51. Extension []byte `json:"extension"`
  52. ExtensionSignature []byte `json:"extension_signature"`
  53. }
  54. // CommitSig converts the Vote to a CommitSig.
  55. func (vote *Vote) CommitSig() CommitSig {
  56. if vote == nil {
  57. return NewCommitSigAbsent()
  58. }
  59. var blockIDFlag BlockIDFlag
  60. switch {
  61. case vote.BlockID.IsComplete():
  62. blockIDFlag = BlockIDFlagCommit
  63. case vote.BlockID.IsNil():
  64. blockIDFlag = BlockIDFlagNil
  65. default:
  66. panic(fmt.Sprintf("Invalid vote %v - expected BlockID to be either empty or complete", vote))
  67. }
  68. return CommitSig{
  69. BlockIDFlag: blockIDFlag,
  70. ValidatorAddress: vote.ValidatorAddress,
  71. Timestamp: vote.Timestamp,
  72. Signature: vote.Signature,
  73. }
  74. }
  75. // VoteSignBytes returns the proto-encoding of the canonicalized Vote, for
  76. // signing. Panics if the marshaling fails.
  77. //
  78. // The encoded Protobuf message is varint length-prefixed (using MarshalDelimited)
  79. // for backwards-compatibility with the Amino encoding, due to e.g. hardware
  80. // devices that rely on this encoding.
  81. //
  82. // See CanonicalizeVote
  83. func VoteSignBytes(chainID string, vote *tmproto.Vote) []byte {
  84. pb := CanonicalizeVote(chainID, vote)
  85. bz, err := protoio.MarshalDelimited(&pb)
  86. if err != nil {
  87. panic(err)
  88. }
  89. return bz
  90. }
  91. func (vote *Vote) Copy() *Vote {
  92. voteCopy := *vote
  93. return &voteCopy
  94. }
  95. // String returns a string representation of Vote.
  96. //
  97. // 1. validator index
  98. // 2. first 6 bytes of validator address
  99. // 3. height
  100. // 4. round,
  101. // 5. type byte
  102. // 6. type string
  103. // 7. first 6 bytes of block hash
  104. // 8. first 6 bytes of signature
  105. // 9. first 6 bytes of vote extension
  106. // 10. timestamp
  107. func (vote *Vote) String() string {
  108. if vote == nil {
  109. return nilVoteStr
  110. }
  111. var typeString string
  112. switch vote.Type {
  113. case tmproto.PrevoteType:
  114. typeString = "Prevote"
  115. case tmproto.PrecommitType:
  116. typeString = "Precommit"
  117. default:
  118. panic("Unknown vote type")
  119. }
  120. return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X %X @ %s}",
  121. vote.ValidatorIndex,
  122. tmbytes.Fingerprint(vote.ValidatorAddress),
  123. vote.Height,
  124. vote.Round,
  125. vote.Type,
  126. typeString,
  127. tmbytes.Fingerprint(vote.BlockID.Hash),
  128. tmbytes.Fingerprint(vote.Signature),
  129. tmbytes.Fingerprint(vote.Extension),
  130. CanonicalTime(vote.Timestamp),
  131. )
  132. }
  133. func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
  134. if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
  135. return ErrVoteInvalidValidatorAddress
  136. }
  137. v := vote.ToProto()
  138. if !pubKey.VerifySignature(VoteSignBytes(chainID, v), vote.Signature) {
  139. return ErrVoteInvalidSignature
  140. }
  141. if vote.Extension != nil && !pubKey.VerifySignature(vote.Extension, vote.ExtensionSignature) {
  142. return ErrVoteInvalidSignature
  143. }
  144. return nil
  145. }
  146. // ValidateBasic performs basic validation.
  147. func (vote *Vote) ValidateBasic() error {
  148. if !IsVoteTypeValid(vote.Type) {
  149. return errors.New("invalid Type")
  150. }
  151. if vote.Height < 0 {
  152. return errors.New("negative Height")
  153. }
  154. if vote.Round < 0 {
  155. return errors.New("negative Round")
  156. }
  157. // NOTE: Timestamp validation is subtle and handled elsewhere.
  158. if err := vote.BlockID.ValidateBasic(); err != nil {
  159. return fmt.Errorf("wrong BlockID: %w", err)
  160. }
  161. // BlockID.ValidateBasic would not err if we for instance have an empty hash but a
  162. // non-empty PartsSetHeader:
  163. if !vote.BlockID.IsNil() && !vote.BlockID.IsComplete() {
  164. return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID)
  165. }
  166. if len(vote.ValidatorAddress) != crypto.AddressSize {
  167. return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes",
  168. crypto.AddressSize,
  169. len(vote.ValidatorAddress),
  170. )
  171. }
  172. if vote.ValidatorIndex < 0 {
  173. return errors.New("negative ValidatorIndex")
  174. }
  175. if len(vote.Signature) == 0 {
  176. return errors.New("signature is missing")
  177. }
  178. if len(vote.Signature) > MaxSignatureSize {
  179. return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
  180. }
  181. if len(vote.Extension) > 0 && len(vote.ExtensionSignature) == 0 {
  182. return errors.New("vote extension signature is missing")
  183. }
  184. return nil
  185. }
  186. // ToProto converts the handwritten type to proto generated type
  187. // return type, nil if everything converts safely, otherwise nil, error
  188. func (vote *Vote) ToProto() *tmproto.Vote {
  189. if vote == nil {
  190. return nil
  191. }
  192. return &tmproto.Vote{
  193. Type: vote.Type,
  194. Height: vote.Height,
  195. Round: vote.Round,
  196. BlockID: vote.BlockID.ToProto(),
  197. Timestamp: vote.Timestamp,
  198. ValidatorAddress: vote.ValidatorAddress,
  199. ValidatorIndex: vote.ValidatorIndex,
  200. Signature: vote.Signature,
  201. Extension: vote.Extension,
  202. ExtensionSignature: vote.ExtensionSignature,
  203. }
  204. }
  205. func VotesToProto(votes []*Vote) []*tmproto.Vote {
  206. if votes == nil {
  207. return nil
  208. }
  209. res := make([]*tmproto.Vote, 0, len(votes))
  210. for _, vote := range votes {
  211. v := vote.ToProto()
  212. // protobuf crashes when serializing "repeated" fields with nil elements
  213. if v != nil {
  214. res = append(res, v)
  215. }
  216. }
  217. return res
  218. }
  219. // FromProto converts a proto generetad type to a handwritten type
  220. // return type, nil if everything converts safely, otherwise nil, error
  221. func VoteFromProto(pv *tmproto.Vote) (*Vote, error) {
  222. if pv == nil {
  223. return nil, errors.New("nil vote")
  224. }
  225. blockID, err := BlockIDFromProto(&pv.BlockID)
  226. if err != nil {
  227. return nil, err
  228. }
  229. vote := new(Vote)
  230. vote.Type = pv.Type
  231. vote.Height = pv.Height
  232. vote.Round = pv.Round
  233. vote.BlockID = *blockID
  234. vote.Timestamp = pv.Timestamp
  235. vote.ValidatorAddress = pv.ValidatorAddress
  236. vote.ValidatorIndex = pv.ValidatorIndex
  237. vote.Signature = pv.Signature
  238. vote.Extension = pv.Extension
  239. vote.ExtensionSignature = pv.ExtensionSignature
  240. return vote, vote.ValidateBasic()
  241. }