CometBFT provides a deterministic, Byzantine fault-tolerant, source of time. Time in CometBFT is defined with the Time field of the block header.
It satisfies the following properties:
h2 = h1 + 1,
H1.Time < H2.Time.
block.LastCommitfield, a range of valid values for the Time field of the block header is defined only by
In the context of CometBFT, time is of type int64 and denotes UNIX time in milliseconds, i.e., corresponds to the number of milliseconds since January 1, 1970. Before defining rules that need to be enforced by Tendermint, the consensus algorithm adopted in CometBFT, so the properties above holds, we introduce the following definition:
Vote.Timefields of the
Votemessages, where the value of
Vote.Timeis counted number of times proportional to the process voting power. As the voting power is not uniform (one process one vote), a vote message is actually an aggregator of the same votes whose number is equal to the voting power of the process that has casted the corresponding votes message.
Let’s consider the following example:
N = 3f+1, where
Nis the total voting power, and
fis the maximum voting power of the faulty processes), so we assume that the faulty processes have at most 23 of voting power. Furthermore, we have the following vote messages in some LastCommit field (we ignore all fields except Time field):
block.LastCommitmessage contains votes of processes p2, p3 and p4. Median is then chosen the following way: the value 98 is counted 27 times, the value 1000 is counted 10 times and the value 500 is counted also 10 times. So the median value will be the value 98. No matter what set of messages with at least
2f+1voting power we choose, the median value will always be between the values sent by correct processes.
We ensure Time Monotonicity and Time Validity properties by the following rules:
let rs denotes
RoundState (consensus internal state) of some process. Then
rs.ProposalBlock.Header.Time == median(rs.LastCommit) &&
rs.Proposal.Timestamp == rs.ProposalBlock.Header.Time.
Furthermore, when creating the
vote message, the following rules for determining
vote.Time field should hold:
rs.LockedBlock is defined then
vote.Time = max(rs.LockedBlock.Timestamp + time.Millisecond, time.Now()), where
denotes local Unix time in milliseconds
rs.Proposal is defined then
vote.Time = max(rs.Proposal.Timestamp + time.Millisecond,, time.Now()),
vote.Time = time.Now()). In this case vote is for
nil so it is not taken into account for
the timestamp of the next block.