Skip to main content
CometBFT can be configured via a TOML file in $CMTHOME/config/config.toml. Some of these parameters can be overridden by command-line flags. For most users, the options in the ##### main base configuration options ##### section are intended to be modified, while config options further below are intended for advanced power users.

Options

The default configuration file created by cometbft init has all the parameters set with their default values. It will look something like the file below; however, double-check by inspecting the config.toml created with your version of cometbft installed:

Empty blocks vs. no empty blocks

create_empty_blocks = true

If create_empty_blocks is set to true in your config, blocks will be created approximately every second (with default consensus parameters). You can regulate the delay between blocks by changing timeout_commit. For example, timeout_commit = "10s" should result in approximately 10-second blocks.

create_empty_blocks = false

In this setting, blocks are created when transactions are received. Note that after block H, CometBFT creates something we call a “proof block” (only if the application hash changed) H+1. The reason for this is to support proofs. If you have a transaction in block H that changes the state to X, the new application hash will only be included in block H+1. If after your transaction is committed, you want to get a light-client proof for the new state (X), you need the new block to be committed in order to do that because the new block has the new application hash for state X. That’s why we create a new (empty) block if the application hash changes. Otherwise, you won’t be able to make a proof for the new state. Additionally, if you set create_empty_blocks_interval to something other than the default (0), CometBFT will create empty blocks even in the absence of transactions every create_empty_blocks_interval. For instance, with create_empty_blocks = false and create_empty_blocks_interval = "30s", CometBFT will only create blocks if there are transactions, or after waiting 30 seconds without receiving any transactions.

Consensus timeouts explained

There’s a variety of information about timeouts in Running in production. You can also find a more detailed explanation in the paper describing the Tendermint consensus algorithm, adopted by CometBFT: The latest gossip on BFT consensus.
Note that in a successful round, the only timeout that we absolutely wait no matter what is timeout_commit. Here’s a brief summary of the timeouts:
  • timeout_propose = how long a validator should wait for a proposal block before prevoting nil
  • timeout_propose_delta = how much timeout_propose increases with each round
  • timeout_prevote = how long a validator should wait after receiving +2/3 prevotes for anything (i.e., not a single block or nil)
  • timeout_prevote_delta = how much timeout_prevote increases with each round
  • timeout_precommit = how long a validator should wait after receiving +2/3 precommits for anything (i.e., not a single block or nil)
  • timeout_precommit_delta = how much timeout_precommit increases with each round
  • timeout_commit = how long a validator should wait after committing a block before starting on the new height (this gives us a chance to receive some more precommits, even though we already have +2/3)

The adverse effect of using inconsistent timeout_propose in a network

Here’s an interesting question: What happens if a particular validator sets a very small timeout_propose, as compared to the rest of the network? Imagine there are only two validators in your network: Alice and Bob. Bob sets timeout_propose to 0s. Alice uses the default value of 3s. Let’s say they both have equal voting power. Given the proposer selection algorithm is a weighted round-robin, you may expect Alice and Bob to take turns proposing blocks, with a result like:
What happens in reality is, however, a little bit different:
That’s because Bob doesn’t wait for a proposal from Alice (prevotes nil). This leaves Alice no chance to commit a block. Note that every block Bob creates needs a vote from Alice to constitute 2/3+. Bob always gets one because Alice has timeout_propose set to 3s. Alice never gets one because Bob has it set to 0s. Imagine now there are ten geographically distributed validators. One of them (Bob) sets timeout_propose to 0s. Others have it set to 3s. Now, Bob won’t be able to move at his own speed because it still needs 2/3 votes of the other validators, and it takes time to propagate those. In other words, the network moves at the speed of time to accumulate 2/3+ of votes (prevotes & precommits), not at the speed of the fastest proposer.
Isn’t block production determined by voting power?
If it were determined solely by voting power, it wouldn’t be possible to ensure liveness. Timeouts exist because the network can’t rely on a single proposer being available and must move on if such proposer is not responding.
How can we address situations where someone arbitrarily adjusts their block production time to gain an advantage?
The impact shown above is negligible in a decentralized network with sufficient decentralization.

The adverse effect of using inconsistent timeout_commit in a network

Let’s look at the same scenario as before. There are ten geographically distributed validators. One of them (Bob) sets timeout_commit to 0s. Others have it set to 1s (the default value). Now, Bob will be the fastest producer because he doesn’t wait for additional precommits after creating a block. If waiting for precommits (timeout_commit) is not incentivized, Bob will accrue more rewards compared to the other 9 validators. This is because Bob has the advantage of broadcasting his proposal early (1 second earlier than the others). But it also makes it possible for Bob to miss a proposal from another validator and prevote nil due to him starting timeout_propose earlier. In other words, if Bob’s timeout_commit is too low compared to other validators, then he might miss some proposals and get slashed for inactivity.