BFT Time is a Byzantine fault-tolerant algorithm for computing block times.
CometBFT
v1.xintroduced Proposer-Based Timestamps (PBTS), intended to be a replacement for BFT Time. Users are strongly encouraged to adopt the PBTS algorithm in new chains, or when upgrading existing chains, as the BFT Time algorithm MAY be deprecated in a future version of CometBFT.
BFT Time computes the Time of a block proposed in height H of consensus
from the Timestamp field of the Precommit messages broadcast by
validators in the commit Round of the previous height H-1.
In order to commit a block, a node needs to receive Precommit messages for
the corresponding BlockID from validators whose cumulative voting power is
more than 2/3 of the total voting power.
The received Precommit messages should refer to the same round, the commit Round.
A set of Precommit messages with the properties above mentioned is a Commit.
A Commit set of height H is included in blocks proposed in height H+1.
BFT Time computes the Time field of a block proposed in height H deterministically
from the LastCommit field of the block, which is a Commit set from
height H-1, using the MedianTime method defined as follows:
MedianTime: the weighted median of Timestamp fields of Precommit
messages forming a Commit set, with weights defined by the validators’ voting powers.
The weighted median is produced by considering the value of each Timestamp
value a number of times proportional to the voting power of the corresponding validator.The median of a set of values is one of the values of the set, so the
Time of a proposed block is one of the Timestamp fields of the Precommit
messages included in the LastCommit set of that block.
Consider the following example:
N < 3F, where N is the total voting
power and F is the maximum voting power of faulty validators).Precommit messages in some Commit field (notice that we
ignore all fields except the validator name and the Timestamp field): (p1, 100), (p2, 98), (p3, 1000), (p4, 500).
We assume that p3 and p4 are faulty validators, as they propose block times
far much higher (far in the future) than p1 and p2.block.LastCommit field contains Precommits of
validators p2, p3 and p4.MedianTime is then chosen the following way: the value 98 (p2) is
counted 27 times, the value 1000 (p3) is counted 10 times and the value 500
(p4) is counted also 10 times. The median value will be 98.Notice that, no matter what set of Precommit messages with at least 2/3 of
the total voting power we choose, the MedianTime value will always be a
value among the Timestamp values produced by correct validators.
By correct here we assume non-malicious validators whose clocks are reasonably
accurated with to time.
In order to implement BFT Time, validators need to set the Timestamp field of
Precommit messages they sign and broadcast, and block proposers need to
compute the block Time from the LastCommit set.
When producing a Precommit message, a validator should set the Timestamp field as follows:
now be the clock time of the validator.LockedBlock is defined, set Timestamp = max(now, LockedBlock.Time + 1ms).ProposalBlock is defined, set Timestamp = max(now, ProposalBlock.Time + 1ms).Timestamp = now.The LockedBlock, if set, is the block for which the validator is issuing a Precommit.
The ProposalBlock is the block proposed in that round; in favorable runs, it
matches the LockedBlock.
The validator in practice proposes the Time for the next block when setting
the Timestamp of its Precommit.
The proposed Time is, by default, the validator’s current clock time.
To ensure Time Monotonicity, the Time of the next block should be
higher than the Time of the block to be committed in the current height.
So if now is smaller than Time, the validator proposes the Time of the block to be committed
plus a small delta, set to 1ms.
The proposer of a round of consensus produces a block to be proposed.
The proposed block must include a Commit set from the commit round of the
previous height, as the block’s LastCommit field.
The Time for the proposed block is then set as Block.Time = MedianTime(block.LastCommit).
Since the block Time is produced in a deterministic way, every node that
receives the proposed block, can validate Block.Time using the same
procedure. Blocks with wrongly computed block times are rejected.
BFT Time guarantees the two main properties for block times:
Time Monotonicity: the production of Timestamp fields for
Precommit messages at correct validators ensures that the Time proposed
for the next block is higher than the Time of the current block.
Since the Time of a block is retrieved from a Precommit
produced by a correct validator, monotonicity is guaranteed.
Byzantine Fault Tolerance: given a Commit set that forms the
LastCommit field, a range of valid values for the Time field of the
block is defined only by Precommit messages produced by correct validators,
i.e., faulty validators cannot arbitrarily influence (increase or decrease) the
Time value.
Notice that the guarantees rely on the fact that the voting power owned by Byzantine validators is limited, more specifically, is less than 1/3 of the total voting power, which is also a requirement for the consensus algorithm.