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.

205 lines
6.0 KiB

  1. # Validator Signing
  2. Here we specify the rules for validating a proposal and vote before signing.
  3. First we include some general notes on validating data structures common to both types.
  4. We then provide specific validation rules for each. Finally, we include validation rules to prevent double-sigining.
  5. ## SignedMsgType
  6. The `SignedMsgType` is a single byte that refers to the type of the message
  7. being signed. It is defined in Go as follows:
  8. ```
  9. // SignedMsgType is a type of signed message in the consensus.
  10. type SignedMsgType byte
  11. const (
  12. // Votes
  13. PrevoteType SignedMsgType = 0x01
  14. PrecommitType SignedMsgType = 0x02
  15. // Proposals
  16. ProposalType SignedMsgType = 0x20
  17. )
  18. ```
  19. All signed messages must correspond to one of these types.
  20. ## Timestamp
  21. Timestamp validation is subtle and there are currently no bounds placed on the
  22. timestamp included in a proposal or vote. It is expected that validators will honestly
  23. report their local clock time. The median of all timestamps
  24. included in a commit is used as the timestamp for the next block height.
  25. Timestamps are expected to be strictly monotonic for a given validator, though
  26. this is not currently enforced.
  27. ## ChainID
  28. ChainID is an unstructured string with a max length of 50-bytes.
  29. In the future, the ChainID may become structured, and may take on longer lengths.
  30. For now, it is recommended that signers be configured for a particular ChainID,
  31. and to only sign votes and proposals corresponding to that ChainID.
  32. ## BlockID
  33. BlockID is the structure used to represent the block:
  34. ```
  35. type BlockID struct {
  36. Hash []byte
  37. PartsHeader PartSetHeader
  38. }
  39. type PartSetHeader struct {
  40. Hash []byte
  41. Total int
  42. }
  43. ```
  44. To be included in a valid vote or proposal, BlockID must either represent a `nil` block, or a complete one.
  45. We introduce two methods, `BlockID.IsZero()` and `BlockID.IsComplete()` for these cases, respectively.
  46. `BlockID.IsZero()` returns true for BlockID `b` if each of the following
  47. are true:
  48. ```
  49. b.Hash == nil
  50. b.PartsHeader.Total == 0
  51. b.PartsHeader.Hash == nil
  52. ```
  53. `BlockID.IsComplete()` returns true for BlockID `b` if each of the following
  54. are true:
  55. ```
  56. len(b.Hash) == 32
  57. b.PartsHeader.Total > 0
  58. len(b.PartsHeader.Hash) == 32
  59. ```
  60. ## Proposals
  61. The structure of a proposal for signing looks like:
  62. ```
  63. type CanonicalProposal struct {
  64. Type SignedMsgType // type alias for byte
  65. Height int64 `binary:"fixed64"`
  66. Round int64 `binary:"fixed64"`
  67. POLRound int64 `binary:"fixed64"`
  68. BlockID BlockID
  69. Timestamp time.Time
  70. ChainID string
  71. }
  72. ```
  73. A proposal is valid if each of the following lines evaluates to true for proposal `p`:
  74. ```
  75. p.Type == 0x20
  76. p.Height > 0
  77. p.Round >= 0
  78. p.POLRound >= -1
  79. p.BlockID.IsComplete()
  80. ```
  81. In other words, a proposal is valid for signing if it contains the type of a Proposal
  82. (0x20), has a positive, non-zero height, a
  83. non-negative round, a POLRound not less than -1, and a complete BlockID.
  84. ## Votes
  85. The structure of a vote for signing looks like:
  86. ```
  87. type CanonicalVote struct {
  88. Type SignedMsgType // type alias for byte
  89. Height int64 `binary:"fixed64"`
  90. Round int64 `binary:"fixed64"`
  91. BlockID BlockID
  92. Timestamp time.Time
  93. ChainID string
  94. }
  95. ```
  96. A vote is valid if each of the following lines evaluates to true for vote `v`:
  97. ```
  98. v.Type == 0x1 || v.Type == 0x2
  99. v.Height > 0
  100. v.Round >= 0
  101. v.BlockID.IsZero() || v.BlockID.IsComplete()
  102. ```
  103. In other words, a vote is valid for signing if it contains the type of a Prevote
  104. or Precommit (0x1 or 0x2, respectively), has a positive, non-zero height, a
  105. non-negative round, and an empty or valid BlockID.
  106. ## Invalid Votes and Proposals
  107. Votes and proposals which do not satisfy the above rules are considered invalid.
  108. Peers gossipping invalid votes and proposals may be disconnected from other peers on the network.
  109. Note, however, that there is not currently any explicit mechanism to punish validators signing votes or proposals that fail
  110. these basic validation rules.
  111. ## Double Signing
  112. Signers must be careful not to sign conflicting messages, also known as "double signing" or "equivocating".
  113. Tendermint has mechanisms to publish evidence of validators that signed conflicting votes, so they can be punished
  114. by the application. Note Tendermint does not currently handle evidence of conflciting proposals, though it may in the future.
  115. ### State
  116. To prevent such double signing, signers must track the height, round, and type of the last message signed.
  117. Assume the signer keeps the following state, `s`:
  118. ```
  119. type LastSigned struct {
  120. Height int64
  121. Round int64
  122. Type SignedMsgType // byte
  123. }
  124. ```
  125. After signing a vote or proposal `m`, the signer sets:
  126. ```
  127. s.Height = m.Height
  128. s.Round = m.Round
  129. s.Type = m.Type
  130. ```
  131. ### Proposals
  132. A signer should only sign a proposal `p` if any of the following lines are true:
  133. ```
  134. p.Height > s.Height
  135. p.Height == s.Height && p.Round > s.Round
  136. ```
  137. In other words, a proposal should only be signed if it's at a higher height, or a higher round for the same height.
  138. Once a proposal or vote has been signed for a given height and round, a proposal should never be signed for the same height and round.
  139. ### Votes
  140. A signer should only sign a vote `v` if any of the following lines are true:
  141. ```
  142. v.Height > s.Height
  143. v.Height == s.Height && v.Round > s.Round
  144. v.Height == s.Height && v.Round == s.Round && v.Step == 0x1 && s.Step == 0x20
  145. v.Height == s.Height && v.Round == s.Round && v.Step == 0x2 && s.Step != 0x2
  146. ```
  147. In other words, a vote should only be signed if it's:
  148. - at a higher height
  149. - at a higher round for the same height
  150. - a prevote for the same height and round where we haven't signed a prevote or precommit (but have signed a proposal)
  151. - a precommit for the same height and round where we haven't signed a precommit (but have signed a proposal and/or a prevote)
  152. This means that once a validator signs a prevote for a given height and round, the only other message it can sign for that height and round is a precommit.
  153. And once a validator signs a precommit for a given height and round, it must not sign any other message for that same height and round.