一条链的区块时间戳由谁说了算,看起来是小事,实际牵着一串安全问题:时间戳能不能被出块的人随意往前推?离线很久再上线的节点能不能被时间戳骗过?CometBFT 给出了两个答案,旧的那套叫 BFT Time,新的那套叫 PBTS(Proposer-Based Timestamps,基于提议者的时间戳)。本文按 CometBFT 仓库里的规范文档拆这套机制,并说明切换是怎么在链上完成的。
旧办法:把时间藏在预提交里
PBTS 规范文档开头先描述它要替换的东西。在 CometBFT 的第一版时间算法里,验证者把自己此刻的本地时钟时间放在预提交消息里带上;提议者收集到足够多的预提交之后,把这些时间按投票权加权的中间值算出来,写成下一个区块的时间。文档给这套算法的评价是容错的:只要失效节点(按投票权计)少于三分之一,算出来的时间就保证落在诚实验证者所报时间的最小值与最大值之间。
文档同时也点明了这套算法的软肋。当投票权中超过二分之一由失效节点构成时(这类情况在正常运行的链上不应该发生,但规范必须讨论它),中位数就不再受诚实节点控制,出块时间可能被拖离真实时间。这就是所谓的时间漂移问题:链上时间会缓慢地跑偏,而很多链的锁定与解锁逻辑恰恰依赖区块时间。
新办法:时间由出块者报,规则由大家验

PBTS 把责任重新分配。区块头里的时间戳现在就是出块者造块那一刻自己本地时钟的读数,不再从上一轮投票里算中位数。官方数据结构文档的写法与此一致:PBTS 情形下该字段是提议者产出区块的时间,即其本地时钟的值;而在 BFT Time 情形下它等于上一次提交里时间戳的加权中位数。
时间不再由共识算出来,但绝不是没人管。规范给验证者设了两道同步参数的闸门,用来判定一个提议的时间是否可接受:precision 是允许的时钟不准程度,message_delay 是允许的消息传播延迟。官方文档对这两个字段有明确的上界约束:precision 不得超过 30 秒,message_delay 不得超过 24 小时,超出会在校验时触发溢出类问题,因此实现层直接封顶。直觉上,验证者是在问:按我允许的最大误差和最大网络延迟,这个时间戳有没有可能是诚实产生的?两道闸门共同决定了出块者能把时间往前推多远——不是任意,但也并非一秒不差。
切换开关与单调性
规范文档还处理了兼容与切换。切换靠共识参数里的一个字段完成:pbts_enable_height,即 PBTS 开始生效的高度。也就是说这套机制是硬分叉式的一次性切换,不是按比例灰度;升级后同一个高度之前用旧算法、之后用新算法。同时,时间戳单调递增的老约束仍在:下一个区块的时间必须大于当前高度区块的时间。BFT Time 文档描述了保证单调的做法——如果按算法算出的时间不大于已提交区块的时间,验证者就提出「那个时间再加一个很小的增量」,规范里这个增量被设为 1 毫秒。PBTS 下同样要保证时间戳严格前进,因此出块者即便在空转也要给出更大的时间值。
规范文档还留了一句给使用者的提醒:CometBFT v1.x 引入了 PBTS,把它当作 BFT Time 的替代品,官方强烈建议新链直接采用 PBTS、老链在升级时改用 PBTS,因为 BFT Time 未来版本可能被废弃。
该看哪一处
如果是在运维一条 CometBFT 系链,PBTS 相关有三处需要逐项核对:共识参数里 pbts_enable_height 有没有设置、设在了哪个高度;precision 与 message_delay 的具体取值(官方给出的上界分别是 30 秒和 24 小时);以及各节点自身时钟同步情况,因为异步网络里的判定最终落在「本地时钟加上允许误差」上。这些字段的当时取值应当从链的创世配置与运行中的节点参数读取,而不要用文档默认值代替——本文按规范描述机制,不构成对任何链安全性或性能收益的判断,也不构成投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。