摘要
x/upgrade 是 Cosmos SDK 模块的一种实现,用于帮助正在运行的 Cosmos 链平滑升级到新的(含破坏性变更的)软件版本。它通过提供一个 PreBlocker 钩子来实现这一点:当达到预定义的升级区块高度后,阻止区块链状态机继续推进。
该模块并不规定治理如何决定执行升级,而只提供一种安全协调升级的机制。如果没有软件层面的升级支持,升级一条在线链是有风险的,因为所有验证者都需要在流程中的完全相同位置暂停其状态机。如果这一步没有正确完成,就可能出现难以恢复的状态不一致。
概念
计划
x/upgrade 模块定义了一个 Plan 类型,用于安排在线升级的发生时间。Plan 可以被安排在某个特定的区块高度执行。
当一个冻结的候选发布版本以及相应的升级 Handler(见下文)达成一致后,就会创建一个 Plan,其中 Plan 的 Name 对应某个特定的 Handler。通常,Plan 是通过治理提案流程创建的,在投票通过后被安排执行。Plan 的 Info 可以包含与升级相关的各种元数据,通常是应用特定的升级信息,会写入链上,例如验证者可自动升级到的 git commit。
Sidecar 进程
如果运行应用二进制的操作员还运行了一个 sidecar 进程,以辅助自动下载并升级二进制文件,那么Info 可以让这一过程无缝完成。这个工具就是 Cosmovisor。
Handler
x/upgrade 模块支持从主版本 X 升级到主版本 Y。为实现这一点,节点操作员必须先将当前二进制升级到一个新的二进制版本,该版本包含与新版本 Y 对应的 Handler。默认假设这个版本已经经过充分测试,并获得了社区的整体认可。这个 Handler 定义了在新二进制 Y 能够成功运行链之前,需要执行哪些状态迁移。自然地,这个 Handler 是应用特定的,而不是按模块定义的。注册 Handler 通过应用中的 Keeper#SetUpgradeHandler 完成。
EndBlock 时,x/upgrade 模块都会检查是否存在应当执行的 Plan(即是否安排在当前高度)。如果存在,就执行对应的 Handler。如果预期某个 Plan 应当执行,但没有注册 Handler,或者二进制升级得太早,节点将以可控方式 panic 并退出。
StoreLoader
x/upgrade 模块还支持将存储迁移作为升级的一部分来处理。StoreLoader 设置了在新二进制能够成功运行链之前需要执行的迁移。这一 StoreLoader 也是应用特定的,而不是按模块定义的。注册该 StoreLoader 通过应用中的 app#SetStoreLoader 完成。
Plan 写入磁盘。
这条信息对于确保 StoreUpgrades 在正确的高度、针对预期升级平稳执行至关重要。它避免了新二进制在每次重启时都重复执行 StoreUpgrades 的可能性。此外,如果同一高度计划了多个升级,Name 将确保这些 StoreUpgrades 只会在计划中的升级处理器内执行。
提案
通常,Plan 是通过治理中的提案进行提出和提交的,提案中包含一条 MsgSoftwareUpgrade 消息。
该提案遵循标准治理流程。如果提案通过,则针对特定 Handler 的 Plan 会被持久化并安排执行。升级也可以通过在新提案中更新 Plan.Height 来延后或提前。
取消升级提案
升级提案可以被取消。存在一种启用治理的MsgCancelUpgrade 消息类型,它可以嵌入提案中,经投票后如果通过,就会移除已安排的升级 Plan。
当然,这要求在升级真正执行之前足够早地意识到该升级并不是一个好主意,以便留出投票时间。
2 * (VotingPeriod + DepositPeriod) + (SafetyDelta)。其中 SafetyDelta 是指升级提案通过之后,到意识到这是个坏主意(由于链外社会共识)的这段可用时间。
在原始 MsgSoftwareUpgrade 提案仍处于投票期间时,也可以提出 MsgCancelUpgrade 提案,只要该 VotingPeriod 结束时间晚于 MsgSoftwareUpgrade 提案。
状态
x/upgrade 模块的内部状态相对精简且简单。状态包含当前处于激活状态的升级 Plan(如果存在),其键为
0x0;如果某个 Plan 被标记为“已完成”,则其键为 0x1。状态还包含应用中所有模块的共识版本。这些版本以大端序 uint64 存储,可通过前缀 0x2 加上对应模块名称(类型为 string)来访问。状态还维护了一个
Protocol Version,可通过键 0x3 访问。
- Plan:
0x0 -> Plan - Done:
0x1 | byte(plan name) -> BigEndian(Block Height) - ConsensusVersion:
0x2 | byte(module name) -> BigEndian(Module Consensus Version) - ProtocolVersion:
0x3 -> BigEndian(Protocol Version)
x/upgrade 模块不包含 genesis state。
事件
x/upgrade 本身不会发出任何事件。任何与提案相关的事件都由 x/gov 模块发出。
客户端
CLI
用户可以使用 CLI 查询并与upgrade 模块交互。
查询
query 命令允许用户查询 upgrade 状态。
applied
applied 命令允许用户查询某个已完成升级实际应用时对应区块高度的区块头。
module versions
module_versions 命令会获取模块名称及其对应共识版本的列表。
如果在命令后附带某个特定模块名称,则只会返回
该模块的信息。
plan
plan 命令会获取当前已安排的升级计划(如果存在)。
交易
upgrade 模块支持以下交易:software-proposal- 提交升级提案:
cancel-software-upgrade- 取消先前已提交的升级提案:
REST
用户可以使用 REST 端点查询upgrade 模块。
已应用计划
AppliedPlan 按名称查询一个先前已应用的升级计划。
当前计划
CurrentPlan 查询当前升级计划。
模块版本
ModuleVersions 从状态中查询模块版本列表。
gRPC
用户可以使用 gRPC 端点查询upgrade 模块。
已应用的计划
AppliedPlan 通过名称查询先前已应用的升级计划。
当前计划
CurrentPlan 查询当前升级计划。
模块版本
ModuleVersions 从状态中查询模块版本列表。
资源
用于进一步了解x/upgrade 模块的(外部)资源列表。
- Cosmos 开发系列:Cosmos 区块链升级 - 这篇博文详细解释了软件升级的工作方式。
Abstract
x/upgrade is an implementation of a Cosmos SDK module that facilitates smoothly
upgrading a live Cosmos chain to a new (breaking) software version. It accomplishes this by
providing a PreBlocker hook that prevents the blockchain state machine from
proceeding once a pre-defined upgrade block height has been reached.
The module does not prescribe anything regarding how governance decides to do an
upgrade, but just the mechanism for coordinating the upgrade safely. Without software
support for upgrades, upgrading a live chain is risky because all of the validators
need to pause their state machines at exactly the same point in the process. If
this is not done correctly, there can be state inconsistencies which are hard to
recover from.
Concepts
Plan
Thex/upgrade module defines a Plan type in which a live upgrade is scheduled
to occur. A Plan can be scheduled at a specific block height.
A Plan is created once a (frozen) release candidate along with an appropriate upgrade
Handler (see below) is agreed upon, where the Name of a Plan corresponds to a
specific Handler. Typically, a Plan is created through a governance proposal
process, where if voted upon and passed, will be scheduled. The Info of a Plan
may contain various metadata about the upgrade, typically application specific
upgrade info to be included on-chain such as a git commit that validators could
automatically upgrade to.
Sidecar Process
If an operator running the application binary also runs a sidecar process to assist in the automatic download and upgrade of a binary, theInfo allows this process to
be seamless. This tool is Cosmovisor.
Handler
Thex/upgrade module facilitates upgrading from major version X to major version Y. To
accomplish this, node operators must first upgrade their current binary to a new
binary that has a corresponding Handler for the new version Y. It is assumed that
this version has fully been tested and approved by the community at large. This
Handler defines what state migrations need to occur before the new binary Y
can successfully run the chain. Naturally, this Handler is application specific
and not defined on a per-module basis. Registering a Handler is done via
Keeper#SetUpgradeHandler in the application.
EndBlock execution, the x/upgrade module checks if there exists a
Plan that should execute (is scheduled at that height). If so, the corresponding
Handler is executed. If the Plan is expected to execute but no Handler is registered
or if the binary was upgraded too early, the node will gracefully panic and exit.
StoreLoader
Thex/upgrade module also facilitates store migrations as part of the upgrade. The
StoreLoader sets the migrations that need to occur before the new binary can
successfully run the chain. This StoreLoader is also application specific and
not defined on a per-module basis. Registering this StoreLoader is done via
app#SetStoreLoader in the application.
Plan to the disk before panicking.
This information is critical to ensure the StoreUpgrades happens smoothly at the correct height and
expected upgrade. It eliminates the chances for the new binary to execute StoreUpgrades multiple
times every time on restart. Also, if there are multiple upgrades planned on the same height, the Name
will ensure these StoreUpgrades take place only in the planned upgrade handler.
Proposal
Typically, aPlan is proposed and submitted through governance via a proposal
containing a MsgSoftwareUpgrade message.
This proposal prescribes to the standard governance process. If the proposal passes,
the Plan, which targets a specific Handler, is persisted and scheduled. The
upgrade can be delayed or hastened by updating the Plan.Height in a new proposal.
Cancelling Upgrade Proposals
Upgrade proposals can be cancelled. There exists a gov-enabledMsgCancelUpgrade
message type, which can be embedded in a proposal, voted on and, if passed, will
remove the scheduled upgrade Plan.
Of course this requires that the upgrade was known to be a bad idea well before the
upgrade itself, to allow time for a vote.
2 * (VotingPeriod + DepositPeriod) + (SafetyDelta) from the beginning of the
upgrade proposal. The SafetyDelta is the time available from the success of an
upgrade proposal and the realization it was a bad idea (due to external social consensus).
A MsgCancelUpgrade proposal can also be made while the original
MsgSoftwareUpgrade proposal is still being voted upon, as long as the VotingPeriod
ends after the MsgSoftwareUpgrade proposal.
State
The internal state of thex/upgrade module is relatively minimal and simple. The
state contains the currently active upgrade Plan (if one exists) by key
0x0 and if a Plan is marked as “done” by key 0x1. The state
contains the consensus versions of all app modules in the application. The versions
are stored as big endian uint64, and can be accessed with prefix 0x2 appended
by the corresponding module name of type string. The state maintains a
Protocol Version which can be accessed by key 0x3.
- Plan:
0x0 -> Plan - Done:
0x1 | byte(plan name) -> BigEndian(Block Height) - ConsensusVersion:
0x2 | byte(module name) -> BigEndian(Module Consensus Version) - ProtocolVersion:
0x3 -> BigEndian(Protocol Version)
x/upgrade module contains no genesis state.
Events
Thex/upgrade does not emit any events by itself. Any and all proposal related
events are emitted through the x/gov module.
Client
CLI
A user can query and interact with theupgrade module using the CLI.
Query
Thequery commands allow users to query upgrade state.
applied
Theapplied command allows users to query the block header for height at which a completed upgrade was applied.
module versions
Themodule_versions command gets a list of module names and their respective consensus versions.
Following the command with a specific module name will return only
that module’s information.
plan
Theplan command gets the currently scheduled upgrade plan, if one exists.
Transactions
The upgrade module supports the following transactions:software-proposal- submits an upgrade proposal:
cancel-software-upgrade- cancels a previously submitted upgrade proposal:
REST
A user can query theupgrade module using REST endpoints.
Applied Plan
AppliedPlan queries a previously applied upgrade plan by its name.
Current Plan
CurrentPlan queries the current upgrade plan.
Module versions
ModuleVersions queries the list of module versions from state.
gRPC
A user can query theupgrade module using gRPC endpoints.
Applied Plan
AppliedPlan queries a previously applied upgrade plan by its name.
Current Plan
CurrentPlan queries the current upgrade plan.
Module versions
ModuleVersions queries the list of module versions from state.
Resources
A list of (external) resources to learn more about thex/upgrade module.
- Cosmos Dev Series: Cosmos Blockchain Upgrade - The blog post that explains how software upgrades work in detail.