- Data Structures
Block
A block consists of a header, transactions, votes (the commit), and a list of evidence of malfeasance (ie. signing conflicting votes).Execution
Once a block is validated, it can be executed against the state. The state follows this recursive equation:InitialState includes the initial consensus parameters and validator set,
and ABCIApp is an ABCI application that can return results and changes to the validator
set (TODO). Execute is defined as:
prevote, precommit & finalizeCommit stages.
The steps to validate a new block are:
- Check the validity rules of the block and its fields.
- Check the versions (Block & App) are the same as in local state.
- Check the chainID’s match.
- Check the height is correct.
- Check the
LastBlockIDcorresponds to BlockID currently in state. - Check the hashes in the header match those in state.
- Verify the LastCommit against state, this step is skipped for the initial height.
- This is where checking the signatures correspond to the correct block will be made.
- Make sure the proposer is part of the validator set.
- Validate bock time.
- Make sure the new blocks time is after the previous blocks time.
- Calculate the medianTime and check it against the blocks time.
- If the blocks height is the initial height then check if it matches the genesis time.
- Validate the evidence in the block. Note: Evidence can be empty
Header
A block header contains metadata about the block and about the consensus, as well as commitments to the data in the current block, the previous block, and the results returned by the application:Version
NOTE: that this is more specifically the consensus version and doesn’t include information like the P2P Version. (TODO: we should write a comprehensive document about versioning that this can refer to)BlockID
TheBlockID contains two distinct Merkle roots of the block. The BlockID includes these two hashes, as well as the number of parts (ie. len(MakeParts(block)))
See MerkleRoot for details.
PartSetHeader
Part
Part defines a part of a block. In CometBFT blocks are broken intoparts for gossip.
Time
CometBFT uses the Google.Protobuf.Timestamp format, which uses two integers, one 64 bit integer for Seconds and a 32 bit integer for Nanoseconds.Data
Data is just a wrapper for a list of transactions, where transactions are arbitrary byte arrays:Commit
Commit is a simple wrapper for a list of signatures, with one for each validator. It also contains the relevant BlockID, height and round:ExtendedCommit
ExtendedCommit, similarly to Commit, wraps a list of votes with signatures together with other data needed to verify them.
In addition, it contains the verified vote extensions, one for each non-nil vote, along with the extension signatures.
CommitSig
CommitSig represents a signature of a validator, who has voted either for nil,
a particular BlockID or was absent. It’s a part of the Commit and can be used
to reconstruct the vote set given the validator set.
NOTE:
ValidatorAddress and Timestamp fields may be removed in the future
(see ADR-25).
ExtendedCommitSig
ExtendedCommitSig represents a signature of a validator that has voted either for nil,
a particular BlockID or was absent. It is part of the ExtendedCommit and can be used
to reconstruct the vote set given the validator set.
Additionally it contains the vote extensions that were attached to each non-nil precommit vote.
All these extensions have been verified by the application operating at the signing validator’s node.
BlockIDFlag
BlockIDFlag represents which BlockID the signature is for.Vote
A vote is a signed message from a validator for a particular block. The vote includes information about the validator signing it. When stored in the blockchain or propagated over the network, votes are encoded in Protobuf.CanonicalVote
CanonicalVote is for validator signing. This type will not be present in a block. Votes are represented viaCanonicalVote and also encoded using protobuf via type.SignBytes which includes the ChainID,
and uses a different ordering of the fields.
For signing, votes are represented via
CanonicalVote and also encoded using protobuf via
type.SignBytes which includes the ChainID, and uses a different ordering of
the fields.
We define a method Verify that returns true if the signature verifies against the pubkey for the SignBytes
using the given ChainID:
CanonicalVoteExtension
Vote extensions are signed using a representation similar to votes. This is the structure to marshall in order to obtain the bytes to sign or verify the signature.Proposal
Proposal contains height and round for which this proposal is made, BlockID as a unique identifier of proposed block, timestamp, and POLRound (a so-called Proof-of-Lock (POL) round) that is needed for termination of the consensus. If POLRound >= 0, then BlockID corresponds to the block that is locked in POLRound. The message is signed by the validator private key.SignedMsgType
Signed message type represents a signed messages in consensus.Signature
Signatures in CometBFT are raw bytes representing the underlying signature. See the signature spec for more.EvidenceList
EvidenceList is a simple wrapper for a list of evidence:Evidence
Evidence in CometBFT is used to indicate breaches in the consensus by a validator. More information on how evidence works in CometBFT can be found hereDuplicateVoteEvidence
DuplicateVoteEvidence represents a validator that has voted for two different blocks
in the same round of the same height. Votes are lexicographically sorted on BlockID.
LightClientAttackEvidence
LightClientAttackEvidence is a generalized evidence that captures all forms of known attacks on
a light client such that a full node can verify, propose and commit the evidence on-chain for
punishment of the malicious validators. There are three forms of attacks: Lunatic, Equivocation
and Amnesia. These attacks are exhaustive. You can find a more detailed overview of this here
LightBlock
LightBlock is the core data structure of the light client. It combines two data structures needed for verification (signedHeader & validatorSet).
The
SignedHeader and ValidatorSet are linked by the hash of the validator set(SignedHeader.ValidatorsHash == ValidatorSet.Hash().