Aptos 区块链上的 Move 代码(例如,Move 模块)可以升级。这允许代码所有者和模块开发者在一个单一、稳定、知名且不变的账户地址下更新和改进他们的合约。如果发生模块升级,该模块的所有消费者将自动接收代码的最新版本(例如,下次与它交互时)。

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

然而,我们注意到,即使是兼容的升级也可能对应用程序和相关的 Move 代码产生危险影响(例如,如果底层模块的语义被修改)。因此,开发者在依赖可以在链上升级的第三方 Move 代码时应谨慎。更多细节请参阅依赖的安全考虑

1. 工作原理

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

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

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

2. 如何升级

要升级已发布的 Move 代码,只需尝试在其先前发布的相同地址重新发布代码。这可以通过遵循使用Aptos CLI进行代码编译和发布的说明来完成。有关示例,请参阅您的第一个 Move 模块教程。

3. 升级策略

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

  • compatible:这些升级必须是向后兼容的,具体而言:
    • 对于存储,新代码中的所有旧结构声明必须相同。这确保了新代码能够正确解释现有存储状态。但是,可以添加新的结构声明。
    • 对于 API,所有现有的公共函数必须具有与以前相同的签名。可以添加新函数,包括公共和入口函数。
  • immutable:代码不可升级,并保证永远不变。

这些策略在强度方面是有序的,即compatible < immutable,即兼容策略弱于不可变策略。链上包的策略只能变强,不能变弱。此外,包的所有依赖项的策略必须强于或等于给定包的策略。例如,一个immutable包不能直接或间接引用一个compatible包。这为用户保证了不会在幕后发生意外的更新。

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

兼容性规则

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

  • 所有现有结构的字段不能更新。这意味着不能添加新字段,也不能修改现有字段。结构能力也不能更改(不能添加新的或删除现有的)。
  • 所有公共和入口函数不能更改其签名(参数类型、类型参数、返回类型)。但是,参数名称可以更改。
  • public(friend)函数被视为私有,因此它们的签名可以任意更改。这是安全的,因为无论如何只有同一包中的模块才能调用友元函数,如果签名更改,它们需要更新。

在更新模块时,如果看到不兼容错误,请务必检查上述规则并修复任何违规行为。

依赖的安全考虑

如上所述,即使是兼容的升级也可能对依赖升级代码的应用程序产生灾难性影响。这些影响可能来自错误,但也可能是恶意升级的结果。例如,升级的依赖项可能突然使所有函数中止,破坏您的 Move 代码的操作。或者,升级的依赖项可能使所有函数执行时突然消耗比升级前更多的 gas。因此,需要谨慎处理对可升级包的依赖:

  • 最安全的依赖当然是一个 “immutable” 包。这保证了依赖永远不会改变,包括其传递依赖。为了更新一个不可变的包,所有者必须引入一个新的主要版本,这实际上就像部署一个新的、独立的包。这是因为主要版本只能通过名称来表示(例如module feature_v1module feature_v2)。然而,并非所有包所有者都愿意将其代码发布为“immutable”,因为这剥夺了在原地修复错误和更新代码的能力。
  • 如果您依赖于一个“compatible”包,强烈建议您了解并理解发布该包的实体。最高级别的保证是当该包由一个去中心化自治组织(DAO)管理时,其中没有单个用户可以发起升级;必须进行投票或类似操作。Aptos 框架就是这种情况。

编程式升级

一般来说,Aptos 通过 Move 模块 aptos_framework::code 提供了在智能合约中的任何地方发布代码的方法。但是,请注意,当前交易中发布的代码只能在该交易结束后执行。

Aptos 框架本身,包括所有的链上管理逻辑,是编程式升级的一个示例。该框架被标记为“兼容”。升级通过特定生成的治理脚本进行。更多细节,请参阅Aptos 治理