Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit an issue.

包升级机制

Aptos 区块链上的 Move 代码(例如 Move 模块)支持升级功能。这使得代码所有者和模块开发者能够在单一、稳定且广知的账户地址下更新和演进他们的合约,而无需更改地址。如果模块发生升级,所有使用该模块的消费者将自动获取最新版本的代码(例如,在他们下次与该模块交互时)。

Aptos 区块链原生支持不同的 升级策略 ,允许 Move 开发者明确定义其代码升级的约束条件。默认策略是 向后兼容 ,这意味着只有当升级确保不会破坏现有资源存储或公共API(包括公共函数)时,才会接受代码升级。这种兼容性检查之所以可行,得益于 Move 强类型的字节码语义。

不过需要注意的是,即使是兼容的升级也可能对应用程序和依赖的 Move 代码产生风险影响(例如,如果底层模块的语义被修改)。因此,开发者在依赖可升级的第三方 Move 代码时应格外谨慎。更多详情请参阅 依赖项的安全注意事项

工作原理

Aptos区块链上的Move代码升级以 Move 包 为粒度进行。包在 Move.toml 清单中指定升级策略:

[package]
name = "MyApp"
version = "0.0.1"
upgrade_policy = "compatible"
...

Aptos 会在 Move 包通过交易发布时检查兼容性。如果被认为不兼容,该交易将中止。

如何升级

要升级已发布的 Move 代码,只需尝试在原先发布的相同地址重新发布代码。这可以通过按照 Aptos CLI的代码编译和发布说明来完成。具体示例可参考 你的第一个 Move 模块 教程。

升级策略

Aptos目前支持两种不同的升级策略:

  • compatible(兼容性升级):这些升级必须保持向后兼容,具体表现为:
    • 存储方面:所有旧的结构体声明必须与新代码保持一致。这确保了存储的现有状态能被新代码正确解析。不过可以添加新的结构体声明。
    • API 方面:所有现有公共函数必须保持相同的函数签名。可以添加新函数,包括公共函数和入口函数。
  • immutable(不可变):代码不可升级,保证永久保持不变。

这些策略按强度排序为 compatible < immutable,即兼容性策略的约束力弱于不可变策略。链上包的策略只能只会变得更强,而不会减弱。此外,一个包的所有依赖项的策略必须强于或等于给定包的策略。例如,一个 immutable 包不能直接或间接引用 compatible 包。这为用户提供了保障,确保不会在底层发生意外的更新。

需要注意的是,上述规则有一个例外:安装在地址 0x10xa 的框架包不受依赖检查的限制。这是必要的,以便可以基于标准库定义一个 immutable 包,这些标准库具有 compatible 策略以允许关键升级和修复。

兼容性规则

当使用 compatible 升级策略时,模块包可以被升级。但是,对已发布现有模块的更新需要兼容并遵循以下规则:

  • 所有现有结构体的字段不能被更新。这意味着不能添加新字段,也不能修改现有字段。
  • 所有公共和入口函数的签名(参数类型、类型参数、返回类型)不能更改。但是,参数名称可以更改。
  • public(friend) 函数被视为私有,因此它们的签名可以任意更改。这是安全的,因为只有同一包中的模块可以调用友元函数,如果签名发生变化,它们也需要更新。
  • 枚举类型升级兼容性规则
  • 结构体/枚举类型上现有的能力不能被移除(但可以添加能力)。

在更新模块时,如果看到不兼容的错误,请确保检查上述规则并修复所有违规行为。

依赖项的安全注意事项

如上所述,即使是兼容性升级,也可能对依赖被升级代码的应用造成灾难性影响。这些影响可能来自于漏洞,但也可能源于恶意升级。例如,一个被升级的依赖项可能会让所有函数突然中止执行,从而破坏你的 Move 代码的运行。又或者,升级后的依赖会让所有函数的执行成本在 gas 上大幅增加。

因此,对于可升级包的依赖,必须谨慎处理:

  • 最安全的依赖当然是 immutable(不可变)包。这类包保证其本身及其所有传递依赖都不会发生改变。要更新一个不可变包,拥有者必须引入一个新的主版本号,这在实践中就像是部署了一个新的、独立的包。这是因为主版本号的区分只能通过名称表达(例如 module feature_v1module feature_v2)。不过,并非所有包的拥有者都愿意将其发布为不可变的,因为这会失去就地修复 bug 和更新代码的能力。

  • 如果你依赖的是一个 compatible(兼容)包,强烈建议你了解并信任发布该包的实体。最高级别的安全保障是该包由去中心化自治组织(DAO)治理,这样单个用户无法发起升级,必须通过投票或类似机制来决策。例如 Aptos 框架就是这种情况。

程序化升级

一般而言,Aptos 通过 Move 模块 aptos_framework::code,提供了一种方式,使你可以在智能合约中的任意位置发布代码。然而,需要注意的是,在当前交易中发布的代码,只有在该交易结束后才能被执行。

Aptos 框架本身(包括所有链上的管理逻辑)就是一个编程式升级的示例。该框架被标记为 compatible(兼容)。其升级通过特定生成的治理脚本完成。欲了解更多详情,请参阅 Aptos 治理