Data Structures
order: 1
Data Structures
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:
- Data Structures
Block
A block consists of a header, transactions, votes (the commit), and a list of evidence of misbehavior (ie. signing conflicting votes).
| Name | Type | Description | Validation |
|---|---|---|---|
| Header | Header | Header corresponding to the block. This field contains information used throughout consensus and other areas of the protocol. To find out what it contains, visit header | Must adhere to the validation rules of header |
| Data | Data | Data contains a list of transactions. The contents of the transaction is unknown to CometBFT. | This field can be empty or populated, but no validation is performed. Applications can perform validation on individual transactions prior to block creation using checkTx. |
| Evidence | EvidenceList | Evidence contains a list of evidence of misbehavior committed by validators. | Can be empty, but when populated the validations rules from evidenceList apply |
| LastCommit | Commit | LastCommit includes one vote for every validator. All votes must either be for the previous block, nil or absent. If a vote is for the previous block it must have a valid signature from the corresponding validator. The sum of the voting power of the validators that voted must be greater than 2/3 of the total voting power of the complete validator set. The number of votes in a commit is limited to 10000 (see types.MaxVotesCount). | Must be empty for the initial height and must adhere to the validation rules of commit. |
Execution
Once a block is validated, it can be executed against the state.
The state follows this recursive equation:
state(initialHeight) = InitialState
state(h+1) <- Execute(state(h), ABCIApp, block(h))
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:
func Execute(state State, app ABCIApp, block Block) State {
// Function ApplyBlock executes block of transactions against the app and returns the new root hash of the app state,
// modifications to the validator set and the changes of the consensus parameters.
AppHash, ValidatorChanges, ConsensusParamChanges := app.ApplyBlock(block)
nextConsensusParams := UpdateConsensusParams(state.ConsensusParams, ConsensusParamChanges)
return State{
ChainID: state.ChainID,
InitialHeight: state.InitialHeight,
LastResults: abciResponses.DeliverTxResults,
AppHash: AppHash,
LastValidators: state.Validators,
Validators: state.NextValidators,
NextValidators: UpdateValidators(state.NextValidators, ValidatorChanges),
ConsensusParams: nextConsensusParams,
Version: {
Consensus: {
AppVersion: nextConsensusParams.Version.AppVersion,
},
},
}
}
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
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:
| Name | Type | Description | Validation |
|---|---|---|---|
| Version | Version | Version defines the application and block versions being used. | Must adhere to the validation rules of Version |
| ChainID | String | ChainID is the ID of the chain. This must be unique to your chain. | ChainID must be less than 50 bytes. |
| Height | uint64 | Height is the height for this header. | Must be > 0, >= initialHeight, and == previous Height+1 |
| Time | Time | The timestamp can be computed using [PBTS][pbts] or [BFT Time][bfttime] algorithms. In case of PBTS, it is the time at which the proposer has produced the block (the value of its local clock). In case of BFT Time, it is equal to the weighted median of timestamps present in the previous commit. | Time must be larger than the Time of the previous block header. The timestamp of the first block should not be smaller than the genesis time. When BFT Time is used, it should match the genesis time (since there's no votes to compute the median with). |
| LastBlockID | BlockID | BlockID of the previous block. | Must adhere to the validation rules of blockID. The first block has block.Header.LastBlockID == BlockID{}. |
| LastCommitHash | slice of bytes ([]byte) | MerkleRoot of the lastCommit's signatures. The signatures represent the validators that committed to the last block. The first block has an empty slices of bytes for the hash. | Must be of length 32 |
| DataHash | slice of bytes ([]byte) | MerkleRoot of the hash of transactions. Note: The transactions are hashed before being included in the merkle tree, the leaves of the Merkle tree are the hashes, not the transactions themselves. | Must be of length 32 |
| ValidatorHash | slice of bytes ([]byte) | MerkleRoot of the current validator set. The validators are first sorted by voting power (descending), then by address (ascending) prior to computing the MerkleRoot. | Must be of length 32 |
| NextValidatorHash | slice of bytes ([]byte) | MerkleRoot of the next validator set. The validators are first sorted by voting power (descending), then by address (ascending) prior to computing the MerkleRoot. | Must be of length 32 |
| ConsensusHash | slice of bytes ([]byte) | Hash of the protobuf encoded consensus parameters. | Must be of length 32 |
| AppHash | slice of bytes ([]byte) | Arbitrary byte array returned by the application after executing and committing the previous block. It serves as the basis for validating any merkle proofs that comes from the ABCI application and represents the state of the actual application rather than the state of the blockchain itself. The first block's block.Header.AppHash is given by InitChainResponse.app_hash. | This hash is determined by the application, CometBFT can not perform validation on it. |
| LastResultHash | slice of bytes ([]byte) | LastResultsHash is the root hash of a Merkle tree built from DeliverTxResponse responses (Log,Info, Codespace and Events fields are ignored). | Must be of length 32. The first block has block.Header.ResultsHash == MerkleRoot(nil), i.e. the hash of an empty input, for RFC-6962 conformance. |
| EvidenceHash | slice of bytes ([]byte) | MerkleRoot of the evidence of Byzantine behavior included in this block. | Must be of length 32 |
| ProposerAddress | slice of bytes ([]byte) | Address of the original proposer of the block. Validator must be in the current validatorSet. | Must be of length 20 |
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)
| Name | type | Description | Validation |
|---|---|---|---|
| Block | uint64 | This number represents the block version and must be the same throughout an operational network | Must be equal to block version being used in a network (block.Version.Block == state.Version.Consensus.Block) |
| App | uint64 | App version is decided on by the application. Read here | block.Version.App == state.Version.Consensus.App |
BlockID
The BlockID contains two distinct Merkle roots of the block. The BlockID includes these two hashes, as
Excerpt (19995 of 57430 characters). Read the whole page on CometBFT specification ↗