# Tendermint中的时间生成策略

By [CaseyLuo](https://paragraph.com/@luoyx) · 2022-03-29

---

相对论告诉我们，绝对时间并不存在。但是分布式系统的节点之前却需要相互协商出一个合理的时间，提供给上层的应用使用。

在Tendermint中，提供了一个确定性的，byzantine容错的时间源BFTTime。时间会被记录在每一个区块中，并且保证下面两个性质：1. Time Monotonicity，递增。2. Time Validity，合法。递增说的是每个区块中的时间戳需要比上一个区块大，而合法指的是区块中的时间必须来源于上一个区块的任一合法验证者的precommit消息中的时间戳。

BFTTime的时间策略是将上一个区块的验证者中的precommit中的时间戳按大小排序，而且因为不同的验证者中质押的stake个数不一，按stake划分权重，取总权重的中间值，中间值落到的验证者的precommit的时间戳即为本区块的时间戳。举个例子，例如存在4个验证者和不同的stake权重，(p1, 23), (p2, 27), (p3, 10) and (p4, 10)，p3和p4是byzantine验证者存在恶意(恶意节点权重20小于总权重70 \* 1/3，因此系统可以正常工作)，他们在上一个区块块precommit的时间戳分别是(p1, 100), (p2, 98), (p3, x), (p4, y)，假设恶意节点故意将时间戳设小，例如x=1，y=2，则中间权重35的验证者节点为p2，因此最终BFTTime=27，符合Time Validity。同样假如x=1000，y=2000，最终的验证者节点还是p2，同样符合Time Validity。最后，即使是一大一小x=1，y=2000，仍然不会破坏Time Validity。

上面说到bftime除了Time Validity还需要满足Time Monotonicity，Time Monotonicity比较简单，只需要验证者取max(本地时间，锁定block的时间戳)，proposer取max(本地时间，proposer时间戳)即可。这里之所以使用上一个提交的block对应的precommit的时间戳，是因为proposer在一开始广播block时无法收集到其他验证者的时间戳。因此这也会带来一个问题，block的时间无法和当前实时时间对应起来。所以在Tendermint中有一个新的时间生成策略Proposer-Based Timestamps，由proposer来决定时间戳， 再由验证者来验证时间的合法性，验证规则为:

ts - PRECISION <= t <= ts + MSGDELAY + PRECISION 

其中t为验证者的本地时间，ts为proposer提出的时间，PRECISION则为预设的机器之间的时间误差，MSGDELAY为预设的消息延迟。假如proposer是byzantine恶意节点，提出了一个过大或者过小的ts，将会被+2/3的合法验证者拒绝。但是我认为其实这里引入预设的PRECISION和MSGDELAY会给系统带来不稳定因素，因为如果设置过大，会导致无法识别出恶意proposer，但是如果设置过小，则会导致正常的proposer无法被通过，从而影响系统可用性。

其实我认为这里更好的解决方案应该是采用truetime的去中心化时间生成算法，在合法的验证者之间广播协商出合法的时间误差范围。

---

*Originally published on [CaseyLuo](https://paragraph.com/@luoyx/tendermint)*
