协调升级是什么?Cosmos 系公链为什么先停在一个高度再重启 图 1
协调升级是什么?Cosmos 系公链为什么先停在一个高度再重启 · 图 1

升级不是换软件那么简单:为什么必须先一起停下

一条 Cosmos 系链要升级到新版本软件时,面对的难题并不是”哪里下载新二进制”,而是几百个验证者如何在同一个时点把状态机停下来。Cosmos SDK 的 x/upgrade 模块就是为此设计的:它提供一个 PreBlocker 钩子,当区块链走到一个预先约定的区块高度时,阻止状态机继续向前出块。模块本身不规定治理如何决定升级,只负责把”全体在同一高度停手”这件事变得可执行。如果所有节点不停在同一个点,有的节点已经按新逻辑执行交易、有的还在按旧逻辑执行,就会造成难以修复的状态不一致。

计划、处理器与停机高度

机制示意(图片由 Agnes 生成,非产品界面或数据图)

升级的第一步是链上提交一个 Plan(计划),里面有两个关键字段:名字和高度。名字对应二进制里注册好的升级处理器(upgrade handler),高度就是全体节点应当停下的区块高度。处理器是一段治理通过时就得随代码发布到位的函数,负责在切换瞬间完成数据迁移,例如把旧参数搬到新的存储位置、初始化新版本引入的模块。到了计划高度,处理器被执行一次,节点随后退出。

这里有个容易踩的坑:官方文档明确写着,如果计划到了该执行的高度、但二进制里没有注册对应的处理器,或者二进制换得太早,节点会直接 panic 退出。也就是说,只改链上的计划参数而不提前把带处理器的软件发到每台机器上,到点全链都会卡死。因此运维顺序永远是先发新二进制(旧节点照常出块),再等高度自然到达。

停下之后:cosmovisor 与重启窗口

节点停在停机高度后,旧二进制会 panic 并等待人工换程序。cosmovisor 是把这一步自动化的进程管理器:它轮询 x/upgrade 模块在升级高度写出的 upgrade-info.json 文件,检测到新计划后可以自动下载新二进制、停掉当前进程、换上新程序再拉起。没配 cosmovisor 的节点则要靠运维在停机窗口内手动完成替换,停多久取决于最慢的那批操作者。

只要累计超过三分之二质押权重的验证者带上新二进制重新上线,出块就恢复;仍留在旧程序上的节点会一直停在那个高度,直到它们也完成升级。Cosmos SDK 的重启窗口通常以小时计,明显长于以太坊那种不停链的分叉方式,这是它用确定性交换实现解耦升级的代价。

谁排定计划:治理提案与安全余量

x/upgrade 模块刻意不规定治理如何决定升级,它只管排定与执行。实践中计划由治理提案创建:提案里带上名字与高度,通过后写入链上状态。官方文档提醒了一个容易被忽略的时间账:如果想保留”发现升级方案有问题、投票取消”的可能,升级高度至少要排在提案启动后的两倍投票期与存款期之和以外,再留一段安全余量——因为取消本身也要走一轮完整的链上投票,来不及投票的取消等于没有取消。高度同样可以延后或提前,办法是用新提案更新 Plan 里的 Height 字段。核查这些事实不需要信任任何节点操作员:upgrade 模块的状态里能直接读到当前活跃计划的名字、高度,以及已完成升级对应的区块高度,任何人都能复核升级是否按约定发生。

与不停链分叉的路线差异

以太坊式升级靠节点在约定时间自动切换规则、链从不停摆;Cosmos 式协调升级则宁可停几个小时,换取”全体干净利落地站在同一高度换程序”的确定性。前者对用户的感知是某一刻规则悄然变了,后者的感知是全链短暂停摆后满血重启。两种设计没有绝对优劣:前者要求客户端实现极其严谨的迁移逻辑,后者把风险集中暴露在一个可以演练、可以延后的停机窗口里。对普通用户,最直接的含义是:当一条 Cosmos 系链宣布升级高度临近时,那段窗口内充值与提款都会变慢甚至暂停,避开窗口操作是最朴素的自保方式。本文只解释机制,不构成任何投资建议。