Validator Signing
Here we specify the rules for validating a proposal and vote before signing. First we include some general notes on validating data structures common to both types. We then provide specific validation rules for each. Finally, we include validation rules to prevent double-sigining.SignedMsgType
TheSignedMsgType is a single byte that refers to the type of the message
being signed. It is defined in Go as follows:
Timestamp
Timestamp validation is subtle and there are currently no bounds placed on the timestamp included in a proposal or vote. It is expected that validators will honestly report their local clock time. The median of all timestamps included in a commit is used as the timestamp for the next block height. Timestamps are expected to be strictly monotonic for a given validator, though this is not currently enforced.ChainID
ChainID is an unstructured string with a max length of 50-bytes. In the future, the ChainID may become structured, and may take on longer lengths. For now, it is recommended that signers be configured for a particular ChainID, and to only sign votes and proposals corresponding to that ChainID.BlockID
BlockID is the structure used to represent the block:nil block, or a complete one.
We introduce two methods, BlockID.IsZero() and BlockID.IsComplete() for these cases, respectively.
BlockID.IsZero() returns true for BlockID b if each of the following
are true:
BlockID.IsComplete() returns true for BlockID b if each of the following
are true:
Proposals
The structure of a proposal for signing looks like:p:
Votes
The structure of a vote for signing looks like:v:
Invalid Votes and Proposals
Votes and proposals which do not satisfy the above rules are considered invalid. Peers gossipping invalid votes and proposals may be disconnected from other peers on the network. Note, however, that there is not currently any explicit mechanism to punish validators signing votes or proposals that fail these basic validation rules.Double Signing
Signers must be careful not to sign conflicting messages, also known as “double signing” or “equivocating”. CometBFT has mechanisms to publish evidence of validators that signed conflicting votes, so they can be punished by the application. Note CometBFT does not currently handle evidence of conflciting proposals, though it may in the future.State
To prevent such double signing, signers must track the height, round, and type of the last message signed. Assume the signer keeps the following state,s:
m, the signer sets:
Proposals
A signer should only sign a proposalp if any of the following lines are true:
Votes
A signer should only sign a votev if any of the following lines are true:
- at a higher height
- at a higher round for the same height
- a prevote for the same height and round where we haven’t signed a prevote or precommit (but have signed a proposal)
- a precommit for the same height and round where we haven’t signed a precommit (but have signed a proposal and/or a prevote)
nil, ie. where BlockID.IsZero() is true. If a
signer has already signed a vote where BlockID.IsZero() is true, it cannot
sign another vote with the same type for the same height and round where
BlockID.IsComplete() is true. Thus only a single vote of a particular type
(ie. 0x01 or 0x02) can be signed for the same height and round.