Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- [`config`] Merge `timeout_prevote` and `timeout_precommit`,
`timeout_prevote_delta` and `timeout_precommit_delta` into `timeout_round`
and `timeout_round_delta` accordingly
([\#2895](https://github.com/cometbft/cometbft/pull/2895))
42 changes: 14 additions & 28 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1109,14 +1109,10 @@ type ConsensusConfig struct {
TimeoutPropose time.Duration `mapstructure:"timeout_propose"`
// How much timeout_propose increases with each round
TimeoutProposeDelta time.Duration `mapstructure:"timeout_propose_delta"`
// How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil)
TimeoutPrevote time.Duration `mapstructure:"timeout_prevote"`
// How much the timeout_prevote increases with each round
TimeoutPrevoteDelta time.Duration `mapstructure:"timeout_prevote_delta"`
// How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil)
TimeoutPrecommit time.Duration `mapstructure:"timeout_precommit"`
// How much the timeout_precommit increases with each round
TimeoutPrecommitDelta time.Duration `mapstructure:"timeout_precommit_delta"`
// How long we wait after receiving +2/3 prevotes/precommits for “anything” (ie. not a single block or nil)
TimeoutVote time.Duration `mapstructure:"timeout_vote"`
// How much the timeout_vote increases with each round
TimeoutVoteDelta time.Duration `mapstructure:"timeout_vote_delta"`
// How long we 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).
Expand All @@ -1142,10 +1138,8 @@ func DefaultConsensusConfig() *ConsensusConfig {
WalPath: filepath.Join(DefaultDataDir, "cs.wal", "wal"),
TimeoutPropose: 3000 * time.Millisecond,
TimeoutProposeDelta: 500 * time.Millisecond,
TimeoutPrevote: 1000 * time.Millisecond,
TimeoutPrevoteDelta: 500 * time.Millisecond,
TimeoutPrecommit: 1000 * time.Millisecond,
TimeoutPrecommitDelta: 500 * time.Millisecond,
TimeoutVote: 1000 * time.Millisecond,
TimeoutVoteDelta: 500 * time.Millisecond,
TimeoutCommit: 1000 * time.Millisecond,
CreateEmptyBlocks: true,
CreateEmptyBlocksInterval: 0 * time.Second,
Expand All @@ -1161,10 +1155,8 @@ func TestConsensusConfig() *ConsensusConfig {
cfg := DefaultConsensusConfig()
cfg.TimeoutPropose = 40 * time.Millisecond
cfg.TimeoutProposeDelta = 1 * time.Millisecond
cfg.TimeoutPrevote = 10 * time.Millisecond
cfg.TimeoutPrevoteDelta = 1 * time.Millisecond
cfg.TimeoutPrecommit = 10 * time.Millisecond
cfg.TimeoutPrecommitDelta = 1 * time.Millisecond
cfg.TimeoutVote = 10 * time.Millisecond
cfg.TimeoutVoteDelta = 1 * time.Millisecond
// NOTE: when modifying, make sure to update time_iota_ms (testGenesisFmt) in toml.go
cfg.TimeoutCommit = 0
cfg.PeerGossipSleepDuration = 5 * time.Millisecond
Expand All @@ -1188,14 +1180,14 @@ func (cfg *ConsensusConfig) Propose(round int32) time.Duration {
// Prevote returns the amount of time to wait for straggler votes after receiving any +2/3 prevotes.
func (cfg *ConsensusConfig) Prevote(round int32) time.Duration {
return time.Duration(
cfg.TimeoutPrevote.Nanoseconds()+cfg.TimeoutPrevoteDelta.Nanoseconds()*int64(round),
cfg.TimeoutVote.Nanoseconds()+cfg.TimeoutVoteDelta.Nanoseconds()*int64(round),
) * time.Nanosecond
}

// Precommit returns the amount of time to wait for straggler votes after receiving any +2/3 precommits.
func (cfg *ConsensusConfig) Precommit(round int32) time.Duration {
return time.Duration(
cfg.TimeoutPrecommit.Nanoseconds()+cfg.TimeoutPrecommitDelta.Nanoseconds()*int64(round),
cfg.TimeoutVote.Nanoseconds()+cfg.TimeoutVoteDelta.Nanoseconds()*int64(round),
) * time.Nanosecond
}

Expand Down Expand Up @@ -1227,17 +1219,11 @@ func (cfg *ConsensusConfig) ValidateBasic() error {
if cfg.TimeoutProposeDelta < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_propose_delta"}
}
if cfg.TimeoutPrevote < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_prevote"}
if cfg.TimeoutVote < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_vote"}
}
if cfg.TimeoutPrevoteDelta < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_prevote_delta"}
}
if cfg.TimeoutPrecommit < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_precommit"}
}
if cfg.TimeoutPrecommitDelta < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_precommit_delta"}
if cfg.TimeoutVoteDelta < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_vote_delta"}
}
if cfg.TimeoutCommit < 0 {
return cmterrors.ErrNegativeField{Field: "timeout_commit"}
Expand Down
12 changes: 4 additions & 8 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,10 @@ func TestConsensusConfig_ValidateBasic(t *testing.T) {
"TimeoutPropose negative": {func(c *config.ConsensusConfig) { c.TimeoutPropose = -1 }, true},
"TimeoutProposeDelta": {func(c *config.ConsensusConfig) { c.TimeoutProposeDelta = time.Second }, false},
"TimeoutProposeDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutProposeDelta = -1 }, true},
"TimeoutPrevote": {func(c *config.ConsensusConfig) { c.TimeoutPrevote = time.Second }, false},
"TimeoutPrevote negative": {func(c *config.ConsensusConfig) { c.TimeoutPrevote = -1 }, true},
"TimeoutPrevoteDelta": {func(c *config.ConsensusConfig) { c.TimeoutPrevoteDelta = time.Second }, false},
"TimeoutPrevoteDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutPrevoteDelta = -1 }, true},
"TimeoutPrecommit": {func(c *config.ConsensusConfig) { c.TimeoutPrecommit = time.Second }, false},
"TimeoutPrecommit negative": {func(c *config.ConsensusConfig) { c.TimeoutPrecommit = -1 }, true},
"TimeoutPrecommitDelta": {func(c *config.ConsensusConfig) { c.TimeoutPrecommitDelta = time.Second }, false},
"TimeoutPrecommitDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutPrecommitDelta = -1 }, true},
"TimeoutVote": {func(c *config.ConsensusConfig) { c.TimeoutVote = time.Second }, false},
"TimeoutVote negative": {func(c *config.ConsensusConfig) { c.TimeoutVote = -1 }, true},
"TimeoutVoteDelta": {func(c *config.ConsensusConfig) { c.TimeoutVoteDelta = time.Second }, false},
"TimeoutVoteDelta negative": {func(c *config.ConsensusConfig) { c.TimeoutVoteDelta = -1 }, true},
"TimeoutCommit": {func(c *config.ConsensusConfig) { c.TimeoutCommit = time.Second }, false},
"TimeoutCommit negative": {func(c *config.ConsensusConfig) { c.TimeoutCommit = -1 }, true},
"PeerGossipSleepDuration": {func(c *config.ConsensusConfig) { c.PeerGossipSleepDuration = time.Second }, false},
Expand Down
12 changes: 4 additions & 8 deletions config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,14 +510,10 @@ wal_file = "{{ js .Consensus.WalPath }}"
timeout_propose = "{{ .Consensus.TimeoutPropose }}"
# How much timeout_propose increases with each round
timeout_propose_delta = "{{ .Consensus.TimeoutProposeDelta }}"
# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil)
timeout_prevote = "{{ .Consensus.TimeoutPrevote }}"
# How much the timeout_prevote increases with each round
timeout_prevote_delta = "{{ .Consensus.TimeoutPrevoteDelta }}"
# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil)
timeout_precommit = "{{ .Consensus.TimeoutPrecommit }}"
# How much the timeout_precommit increases with each round
timeout_precommit_delta = "{{ .Consensus.TimeoutPrecommitDelta }}"
# How long we wait after receiving +2/3 prevotes/precommits for “anything” (ie. not a single block or nil)
timeout_vote = "{{ .Consensus.TimeoutVote }}"
# How much the timeout_vote increases with each round
timeout_vote_delta = "{{ .Consensus.TimeoutVoteDelta }}"
# How long we 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).
Expand Down
68 changes: 21 additions & 47 deletions docs/references/config/config.toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -1611,79 +1611,53 @@ round of consensus will adopt increased timeout durations.
Timeouts increase linearly over rounds, so that the `timeout_propose` adopted
in round `r` is `timeout_propose + r * timeout_propose_delta`.

### consensus.timeout_prevote
### consensus.timeout_vote

How long a node waits, after receiving +2/3 conflicting prevotes, before pre-committing nil.
How long a node waits, after receiving +2/3 conflicting prevotes/precommits, before pre-committing nil/going into a new round.

```toml
timeout_prevote = "1s"
timeout_vote = "1s"
```

| Value type | string (duration) |
|:--------------------|:------------------|
| **Possible values** | &gt;= `"0s"` |

#### Prevotess

A validator that receives +2/3 prevotes for a block, precommits that block.
If it receives +2/3 prevotes for nil, it precommits nil.
But if prevotes are received from +2/3 validators, but the prevotes do not
match (e.g., they are for different blocks or for blocks and nil), the
validator waits for `timeout_prevote` time before precommiting nil.
validator waits for `timeout_vote` time before precommiting nil.
This gives the validator a chance to wait for additional prevotes and to
possibly observe +2/3 prevotes for a block.

Setting `timeout_prevote` to `0s` means that the validator will not wait
for additional prevotes (other than the mandatory +2/3) before precommitting nil.
This has important liveness implications and should be avoided.

### consensus.timeout_prevote_delta

How much the `timeout_prevote` increases with each round.

```toml
timeout_prevote_delta = "500ms"
```

| Value type | string (duration) |
|:--------------------|:------------------|
| **Possible values** | &gt;= `"0ms"` |

Consensus timeouts are adaptive.
This means that when a round of consensus fails to commit a block, the next
round of consensus will adopt increased timeout durations.
Timeouts increase linearly over rounds, so that the `timeout_prevote` adopted
in round `r` is `timeout_prevote + r * timeout_prevote_delta`.

### consensus.timeout_precommit

How long a node waits, after receiving +2/3 conflicting precommits, before moving to the next round.

```toml
timeout_precommit = "1s"
```

| Value type | string (duration) |
|:--------------------|:------------------|
| **Possible values** | &gt;= `"0s"` |
#### Precommits

A node that receives +2/3 precommits for a block commits that block.
This is a successful consensus round.
If no block gathers +2/3 precommits, the node cannot commit.
This is an unsuccessful consensus round and the node will start an additional
round of consensus.
Before starting the next round, the node waits for `timeout_precommit` time.
Before starting the next round, the node waits for `timeout_vote` time.
This gives the node a chance to wait for additional precommits and to possibly
observe +2/3 precommits for a block, which would allow the node to commit that
block in the current round.

Setting `timeout_precommit` to `0s` means that the validator will not wait
for additional precommits (other than the mandatory +2/3) before moving to the
next round.
This has important liveness implications and should be avoided.
#### Warning

Setting `timeout_vote` to `0s` means that the validator will not wait for
additional prevotes/precommits (other than the mandatory +2/3) before
precommitting nil/moving to the next round. This has important liveness
implications and should be avoided.

### consensus.timeout_vote_delta

How much the `timeout_vote` increases with each round.

### consensus.timeout_precommit_delta
How much the timeout_precommit increases with each round.
```toml
timeout_precommit_delta = "500ms"
timeout_vote_delta = "500ms"
```

| Value type | string (duration) |
Expand All @@ -1693,8 +1667,8 @@ timeout_precommit_delta = "500ms"
Consensus timeouts are adaptive.
This means that when a round of consensus fails to commit a block, the next
round of consensus will adopt increased timeout durations.
Timeouts increase linearly over rounds, so that the `timeout_precommit` adopted
in round `r` is `timeout_precommit + r * timeout_precommit_delta`.
Timeouts increase linearly over rounds, so that the `timeout_vote` adopted
in round `r` is `timeout_vote + r * timeout_vote_delta`.

### consensus.timeout_commit

Expand Down
3 changes: 1 addition & 2 deletions internal/consensus/invalid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ func TestReactorInvalidPrecommit(t *testing.T) {
css, cleanup := randConsensusNet(t, n, "consensus_reactor_test", newMockTickerFunc(true), newKVStore,
func(c *cfg.Config) {
c.Consensus.TimeoutPropose = 3000 * time.Millisecond
c.Consensus.TimeoutPrevote = 1000 * time.Millisecond
c.Consensus.TimeoutPrecommit = 1000 * time.Millisecond
c.Consensus.TimeoutVote = 1000 * time.Millisecond
})
defer cleanup()

Expand Down
2 changes: 1 addition & 1 deletion internal/consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2839,7 +2839,7 @@ func TestStartNextHeightCorrectlyAfterTimeout(t *testing.T) {
signAddVotes(cs1, types.PrecommitType, chainID, blockID, true, vs3)

// wait till timeout occurs
ensureNewTimeout(precommitTimeoutCh, height, round, cs1.config.TimeoutPrecommit.Nanoseconds())
ensureNewTimeout(precommitTimeoutCh, height, round, cs1.config.TimeoutVote.Nanoseconds())

ensureNewRound(newRoundCh, height, round+1)

Expand Down