Skip to main content
Here we describe the data structures in the CometBFT blockchain and the rules for validating them. The CometBFT blockchain consists of a short list of data types:

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:
where 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:
Validating a new block is first done prior to the 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 LastBlockID corresponds 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
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

The BlockID 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 into parts 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 via CanonicalVote 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 here

DuplicateVoteEvidence

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().

SignedHeader

The SignedhHeader is the header accompanied by the commit to prove it.

ValidatorSet

Validator

Address

Address is a type alias of a slice of bytes. The address is calculated by hashing the public key using sha256 and truncating it to only use the first 20 bytes of the slice.

ConsensusParams

BlockParams

EvidenceParams

ValidatorParams

VersionParams

Proof