This document overviews the Proposer-Based Timestamp (PBTS) algorithm introduced in CometBFT version v1.0. It outlines the core functionality of the algorithm and details the consensus parameters that govern its operation.
The PBTS algorithm defines a way for a blockchain to create block timestamps that are within a reasonable bound of the validators’ clocks on the network. It replaces the BFT Time algorithm for timestamp calculation and assignment, which computes the timestamp of a block using the timestamps aggregated from precommit messages.
Each block produced by CometBFT contains a timestamp, represented by the Time
field of the block’s Header
.
The timestamp of each block is expected to be a meaningful representation of time that is useful for the protocols and applications built on top of CometBFT. The following protocols and application features require a reliable source of time:
The PBTS algorithm is not enabled by default in CometBFT v1.0.
If a network upgrades to CometBFT v1.0, it will still use the BFT Time algorithm until PBTS is enabled. The same applies to new networks that do not change the default values for consensus parameters in the genesis file.
Enabling PBTS requires configuring the consensus parameters
that govern the operation of the algorithm.
There are two SynchronyParams
, Precision
and MessageDelay
, used to
validate block timestamps, as described in the following.
And a FeatureParams.PbtsEnableHeight
that defines the height from which PBTS
is adopted.
When a validator creates a new block, it reads the time from its local clock and uses this reading as the timestamp for the block. The proposer of a block is thus free to select the block timestamp, but this timestamp must be validated by other nodes in the network.
When each validator on the network receives a proposed block, it performs a
series of checks to ensure that the block can be considered valid as a
candidate to be the next block in the chain.
If the block is considered invalid, the validator issues a nil
prevote,
signaling to the rest of the network that the proposed block is not valid.
The PBTS algorithm performs a validity check on the timestamp of proposed blocks. This only applies to the first time at which a block is proposed. If the same block is re-proposed in a future round because it was deemed valid by the network, this check is not performed. Refer to the PBTS specification for more details.
When a validator receives a proposal for a new block, it ensures that the timestamp in
the proposal is within a bound of the validator’s local clock.
For that it uses Precision
and MessageDelay
consensus parameters,
which are the same across all nodes for a given height.
Specifically, the algorithm checks that the proposed block’s timestamp is
no more than Precision
greater than the node’s local clock
(i.e., not in the future)
and no less than MessageDelay + Precision
behind the node’s local clock
(i.e., not too far in the past).
If the proposed block’s timestamp is within the window of acceptable
timestamps, the timestamp is considered timely.
If the block timestamp is not timely, the validator rejects the proposed block by
issuing a nil
prevote.
The PBTS algorithm requires the clocks of the validators in the network to be
within Precision
of each other. In practice, this means that validators
should periodically synchronize their clocks, e.g. to a reliable NTP server.
Validators whose clocks drift too far away from the rest of the network will no
longer propose blocks with valid timestamps. Additionally, they will not consider
the timestamps of blocks proposed by their peers to be valid either.
The functionality of the PBTS algorithm is governed by two consensus
parameters: the synchronous parameters Precision
and MessageDelay
.
An additional consensus parameter PbtsEnableHeight
is used to enable PBTS
when instantiating a new network or when upgrading an existing network that
uses BFT Time.
Consensus parameters are configured through the genesis file, for new chains, or by the ABCI application, for new and existing chains, and are the same across all nodes in the network at any given height.
SynchronyParams.Precision
The Precision
parameter configures the acceptable upper-bound of clock drift
among all of the validators in the network.
Any two validators are expected to have clocks that differ by at most
Precision
at any given instant.
The Precision
parameter is of time.Duration
type.
Networks should choose a Precision
that is large enough to represent the
worst-case for the clock drift among all participants.
Due to the leap second events,
it is recommended to set Precision
to at least 500ms
.
SynchronyParams.MessageDelay
The MessageDelay
parameter configures the acceptable upper-bound for the
end-to-end delay for transmitting a Proposal
message from the proposer to
all validators in the network.
The MessageDelay
parameter is of time.Duration
type.
Networks should choose a MessageDelay
that is large enough to represent the
delay for a Proposal
message to reach all participants.
As Proposal
messages are fixed-size, this delay should not depend, a priori,
on the size of proposed blocks.
But it does depend on the number of nodes in the network, the latency of their
connections, and the level of congestion in the network.
FeatureParams.PbtsEnableHeight
The PbtsEnableHeight
parameter configures the first height at which the PBTS
algorithm should be adopted for generating and validating block timestamps in a network.
The PbtsEnableHeight
parameter is an integer.
While PbtsEnableHeight
is set to 0
, the network will adopt the legacy BFT
Time algorithm.
When PbtsEnableHeight
is set to a height H > 0
, the network will switch to
the PBTS algorithm from height H
on.
The network will still adopt the legacy BFT Time algorithm to produce block
timestamps until height H - 1
, and to validate block timestamps produced in
heights up to H - 1
.
The enable height H
must be a future height when it is configured, namely it
can only be set to a height that is larger than the current blockchain height.
Once PbtsEnableHeight
is set and the PBTS algorithm is enabled (i.e., from height
PbtsEnableHeight
), it is not possible to return to the legacy BFT Time algorithm.
The switch to PBTS is therefore irreversible.
Finally, if PbtsEnableHeight
is set to InitialHeight
in the genesis file or by the
ABCI InitChain
method, the network will adopt PBTS from the initial
height. This is the recommended setup for new chains.
When configuring a network to adopt the PBTS algorithm, the following steps must be considered:
SynchronyParams.Precision
is
reasonable.SynchronyParams.MessageDelay
is
reasonable and large enough to reflect the maximum expected delay for messages in the network.
Setting this parameter to a small value may impact the progress of the
network, namely blocks may take very long to be committed.
Vote
and Proposal
) over time and define an
empirical distribution of message delays.
Then pick as value for the MessageDelay
parameter, a high percentile of
this distribution (e.g., the 99th or 99.9th percentiles).Observation 3. is important because a network that sets
SynchronyParams.MessageDelay
to a small value is likely to suffer from long block latencies
and even, in extreme cases, from the complete halt of the network.
By a small value here we mean a message delay that is not enough for an important
portion of the validators to receive the Proposal
message broadcast by the
proposer of a round within the configured message delay.
If the subset of validators that are unlikely to receive the proposal within the
configured SynchronyParams.MessageDelay
hold more than 1/3 of the total
voting power of the network, the network could stop producing blocks
indefinitely.
To prevent the network from halting due to the configuration of a small value
for SynchronyParams.MessageDelay
, we have introduced the concept of
adaptive synchronous parameters.
In summary, this means that the synchrony parameters adopted to verify whether
a proposal timestamp is timely are relaxed as more rounds are required to
commit a block.
The maximum message delay for round 0 is still the configured
SynchronyParams.MessageDelay
; most blocks are committed in round 0, so there
are no changes for the regular case.
From round 1, the maximum message delay adopted by PBTS slowly increases, at a
rate of 10% per round.
As a result, the adopted maximum message delay will eventually converge to the
actual message delay observed in the network.
While this solution prevents the network from halting, it still delays the
commit of a block by several rounds.
For example, if the configured SynchronyParams.MessageDelay
is 0.5s but an
important portion of nodes regularly receive the Proposal
message after 1s,
between 7 and 8 rounds will be necessary to commit a block.
This is an important performance penalty that network operators must avoid at
all costs. Upon noticing this problem, as the network will not halt because of this,
network operators can agree to increase the value of SynchronyParams.MessageDelay
in order to fix the problem.
Observation 4. is important because, with the adoption of PBTS, block times are expected to converge to values that bear resemblance to real time. At the same time, the property of monotonicity of block times is guaranteed by both BFT Time and PBTS. This means that proposers using PBTS will wait until the time they read from their local clocks becomes bigger than the time of the last committed block before proposing a new block.
As a result, if the time of the last block produced using BFT Time is too far in
the future, then the first block produced using PBTS will take very long to be
committed: the time it takes for the clock of the proposer to reach the time of
the previously committed block.
To prevent this from happening, first, follow recommendation 1., i.e., synchronize
the validators’ clocks.
Then wait until the block times produced by BFT Time converge to values that do
not differ too much from real time.
This may take a long time, because in BFT Time if the value a validator reads
from its local clock is smaller than the time of the previous block, then the
time it sets to a new block will be the time of the previous block plus 1ms
.
It may take a while, but block times will eventually converge to real time.
SynchronyParams
consensus parameters adopted by PBTS.