Sway 破坏性版本发布清单:实验性功能晋级、forc migrate 迁移注册与文档收尾全流程
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
本篇技术指南以 Sway 仓库内docs/breaking-release-checklist.md这份破坏性(Breaking)版本发布检查清单为骨架,系统讲解 Sway 编译器如何通过"实验性功能(Experimental Features)+forc migrate迁移工具"来受控引入破坏性变更的完整生命周期。你将掌握:实验性功能开关的定义与优先级、forc migrate三个子命令与迁移步骤的注册/注销机制、将实验性功能转正为稳定功能时需要清理的编译器条件代码、Sway 代码库、E2E 测试与 CI 配置,以及破坏性版本发布前必须完成的文档同步工作——这份清单正是维护者每次发布破坏性版本时的"免检手册"。
为什么需要这份清单:Sway 的破坏性变更管理机制
Sway 语言与编译器在演进过程中,会以受控的方式引入可能破坏现有合约编译结果的新特性。为此,仓库中实现了一套"实验性功能"(Experimental Features)机制,其核心设计目标有三类(见 实验性功能参考文档):
- 承载开发期不稳定的较大语言特性(例如 References 引用特性);
- 以受控方式引入破坏性变更(例如 Partial equivalence 部分等价比较);
- 在不兼容变更发生时保留旧编译器行为作为退路(例如 New hashing 新哈希方案)。
这套机制保证了:破坏性变更不是"一夜间全量生效",而是先以带开关的实验性功能形式提供给早期采用者,待稳定后再在某个破坏性版本中"转正"。而docs/breaking-release-checklist.md正是这个"转正并发布"阶段的操作清单,它把整个发布流程拆解为四大检查项,确保实验性功能从"带门控的试验品"平滑过渡为"默认开启的稳定行为",同时不遗留任何测试、文档或迁移工具的"半成品"状态。
实验性功能的定义与开关机制(源码级)
所有实验性功能都在独立的 cratesway-features中集中注册,其入口为 sway-features/src/lib.rs。该文件通过features!宏一次性生成Feature枚举、ExperimentalFeatures结构体及其解析逻辑,当前仓库注册的实验性功能如下(enabled表示是否默认开启):
| Feature(功能名) | 默认值 | 用途 |
|---|---|---|
new_encoding | true | 新的编码(encoding v1)方案,替代即将退位的 encoding v0 |
references | true | 引用(References)类型特性 |
new_hashing | true | 新哈希方案,改变字符串、数组等类型的哈希结果 |
str_array_no_padding | false | 字符串数组str[N]去除 8 字节对齐填充的新运行时布局 |
dynamic_storage | false | 动态存储特性 |
在编译器内部,每个功能对应的条件编译参数统一为experimental_<feature_name>(如experimental_new_hashing),由Feature::CFG常量批量生成(见sway-features/src/lib.rs中stringify!([<experimental_ $name:snake>])的宏展开)。当某功能被关闭时,编译器会通过FeatureIsDisabled编译错误提示用户,并附上该功能的追踪地址。
实验性功能支持三种粒度的开关方式,且存在严格的覆盖优先级(该顺序直接写死在ExperimentalFeatures::new的文档注释与实现中):
Forc.toml中[project]下的experimental字段(无特定顺序);- CLI 参数
--no-experimental(禁用); - CLI 参数
--experimental(启用); - 环境变量
FORC_NO_EXPERIMENTAL(禁用); - 环境变量
FORC_EXPERIMENTAL(启用)。
即:环境变量覆盖 CLI 参数,CLI 参数覆盖Forc.toml配置。Forc.toml中未列出的功能则使用其默认开关值。对应的命令行示例如下:
# Forc.toml: experimental = { some_feature = true, some_other_feature = false } forc build --experimental some_feature --no-experimental some_other_feature forc build --experimental some_feature_1,some_feature_2 FORC_EXPERIMENTAL=some_feature,other_feature forc build FORC_NO_EXPERIMENTAL=some_feature,other_feature forc build这些开关还支持配合#[cfg(experimental_<feature> = true/false)]属性进行条件编译,让同一份代码在两个行为模式下共存(详见 attributes 文档 与 experimental_features.md):
#[cfg(experimental_some_feature = true)] fn conditionally_compiled() { log("仅在启用 some_feature 时编译"); } #[cfg(experimental_some_feature = false)] fn conditionally_compiled() { log("仅在禁用 some_feature 时编译"); } #[cfg(experimental_some_feature = true)] #[cfg(experimental_some_other_feature = true)] fn conditionally_compiled() { log("仅当两个实验性功能都启用时编译"); }正是这套cfg(experimental_*)门控,让同一次破坏性变更可以在仓库内(std标准库、E2E 测试、语言内测试等)长期共存两套实现,这也是清单中"移除条件代码"工作如此繁重的原因。
检查项一:确保最新补丁版本中的 forc migrate 已包含全部迁移步骤
破坏性版本发布的前置条件是:在破坏性版本之前的最后一个补丁(patch)版本中,forc migrate工具必须已经包含本次破坏性变更所需的全部迁移步骤。这意味着迁移能力必须先于破坏性版本本身交付给用户,让用户在升级前就能提前预览、规划乃至执行迁移。
forc migrate 插件与三个子命令
forc migrate是一个 forc 插件,源码位于 forc-plugins/forc-migrate,CLI 入口在 forc-plugins/forc-migrate/src/cli/mod.rs,它提供三个子命令:
forc migrate show:列出即将到来的破坏性变更功能及其迁移步骤。输出"Breaking change features:"清单,并按执行方式统计 "Migration steps (N manual, N semiautomatic, N automatic)",随后逐条列出步骤,每步用[M](Manual 手动)、[S](Semiautomatic 半自动)、[A](Automatic 自动)标注(见 show.rs)。forc migrate check:对迁移步骤做 dry-run(预演),只报告代码中需要处理的位置而不实际改动源码,最后输出"Migration effort"(迁移工作量)汇总,统计每步的发生次数(Occurrences)并按count × duration估算耗时;若没有任何需要迁移的位置,则提示 "Project is compatible with the next breaking change version of Sway"(见 check.rs)。forc migrate run:真正执行迁移步骤并引导开发者走完整个迁移流程(见 run.rs),支持--path <path>指定项目、--offline离线模式、--locked锁定依赖等参数,并且会一并迁移测试代码(源码中include_tests = true)。如果项目无法编译,工具会提示检查是否遗漏了--experimental <feature_1>,<feature_2>参数。
forc migrate show # 查看即将到来的破坏性变更与迁移步骤 forc migrate check # 预演迁移,报告需要处理的位置与工作量 forc migrate run # 引导执行迁移 forc migrate run --path my_project --offline迁移步骤的注册机制
迁移步骤集中定义在 forc-plugins/forc-migrate/src/migrations/mod.rs。每个破坏性变更功能对应一个子模块(如new_hashing、str_array_layout、partial_eq、references等),其中定义若干MigrationStep。MigrationStep包含四个字段:
title:步骤标题,格式为对开发者建议的续句("You should <title>"),手动步骤的标题以 "Review" 开头;duration:单个典型出现点的手动迁移耗时估计(分钟),只有全自动步骤允许为 0;kind:步骤种类(见下);help:面向开发者的短帮助文本,自动修改代码的步骤以 "Migration will" 开头。
kind分为三种(MigrationStepKind枚举):
Instruction(InstructionFn):纯指导型步骤,只分析程序并返回需要开发者手动处理的位置(Occurrences),不改动源码,归类为 Manual;CodeModification(CodeModificationFn, manual_actions, continue):自动修改源码的步骤,可能附带迁移后仍需开发者手动完成的动作列表(manual_actions);若无手动动作则为全自动(Automatic),否则为半自动(Semiautomatic);Interaction(InstructionFn, InteractionFn, manual_actions, continue):先给指导、再与开发者交互征询决定的步骤,开发者可选择执行、跳过或推迟(InteractionResponse中的ExecuteStep/StepNotNeeded/PostponeStep),归类为 Semiautomatic。
所有步骤集中注册在MIGRATION_STEPS常量中(按功能分组,见migrations/mod.rs中MIGRATION_STEPS定义,当前注册了new_hashing与str_array_no_padding两个功能各自的 Review 步骤),并经过assert_migration_steps_consistency做一致性校验:每个功能只能出现一次、步骤标题必须唯一、仅全自动步骤可设零耗时。get_migration_steps_or_return!宏则在步骤为空时提示 "There are currently no migration steps defined for the upcoming breaking change version of Sway" 并提前返回——这正是"未注册任何迁移步骤"状态的标准输出,也就是清单中第三步"注销"后的表现。
作为实例,new_hashing.rs 中的步骤REVIEW_EXISTING_USAGES_OF_STORAGE_MAP_SHA256_AND_KECCAK256是一个典型的 Instruction 步骤:它提示开发者新哈希会改变str、str[N]、[T; N]、raw_slice、Vec<T>、Bytes等类型的哈希值,需要审查这些类型是否作为StorageMap的 key、是否出现在自定义存储类型中、是否被sha256/keccak256直接哈希;str_array_layout.rs 则针对字符串数组运行时布局变更给出数据迁移建议(用[u8; M]模拟旧填充读取存量数据)。
检查项二:将实验性功能转正为稳定功能
破坏性版本中,实验性功能要被"晋升"为默认且不可关闭的标准行为,这要求彻底移除围绕该功能的全部门控与条件分支。清单列出了五个子任务:
1. 移除编译器中的 feature flag 与全部条件代码
从sway-features的features!宏列表中删除该功能的注册项,并清理编译器(sway-core等)内部所有FeatureIsDisabled错误路径、is_enabled_for_cfg查询及围绕开关if/else分支的代码,使新行为成为唯一路径。
2. 移除 Sway 代码库中的 experimental cfg 属性
在sway仓库内所有 Sway 代码(std标准库 sway-lib-std、E2E 测试、语言内测试等)中,删除所有#[cfg(experimental_<feature> = ...)]属性及其包裹的旧实现分支,只保留新行为对应的代码,让同一份源码不再需要按开关编译。
3. 删除 E2E 测试中的 test. .toml 文件
E2E 测试位于test/src/e2e_vm_tests,每个测试用例目录下带有test.toml之类的配置。针对实验性功能,测试通过test.<feature>.toml这类按功能命名的配置文件来指定在特定开关组合下运行(例如指定--experimental dynamic_storage的专用测试组)。转正后这些按功能拆分的测试配置不再有意义,应整体删除,让测试回归到默认编译路径下执行。
4. 移除 ci.yml 中的实验性功能测试
仓库 CI 工作流 .github/workflows/ci.yml 中维护着针对各实验性功能的专项测试任务,例如对 sdk-harness 与语言内测试分别以不同开关组合构建:
# 关闭 new_hashing(验证旧哈希行为仍可用) - run: cargo run --locked --release -p forc -- build --locked --path ./test/src/sdk-harness --no-experimental new_hashing --output-directory ./test/src/sdk-harness/out # 开启 str_array_no_padding / dynamic_storage(验证新行为) - run: cargo run --locked --release -p forc -- build --locked --path ./test/src/sdk-harness --experimental str_array_no_padding --output-directory ./test/src/sdk-harness/out - run: ./test/src/in_language_tests/run_in_language_tests.sh --experimental dynamic_storage --filter 'storage'功能转正后,这些以--experimental/--no-experimental拆分 CI 矩阵的步骤应从ci.yml中移除,只保留稳定默认配置下的测试。
5. 关闭 GitHub 追踪问题(tracking issues)
每个实验性功能在仓库中都有一个带tracking-issue标签的追踪问题,记录特性的详细描述与引入的破坏性变更(当前活跃与已集成的功能清单见 experimental_features.md 中的说明)。功能转正后,关闭对应的 tracking issue,标志着该功能的实验期正式结束。
检查项三:在破坏性版本中注销迁移步骤(但保留代码作为示例)
迁移步骤注册表MIGRATION_STEPS中关于该功能的步骤要"注销(unregister)",即不再作为活跃迁移步骤对外提供。但清单特别强调:不要删除(Do not delete)这些迁移实现。其理由在migrations/mod.rs的注释中写得很明确:
Change those steps for every new breaking change version of Sway, by removing the previous steps and adding the ones relevant for the next breaking change version.
保留旧迁移有两个目的:其一,它们可以作为未来类似破坏性变更的迁移步骤范例;其二,它们承担"学习与测试"用途——migrations/mod.rs中甚至专门保留了demo子模块,内含用于学习与测试迁移工具的演示迁移("The specialdemosubmodule contains demo migrations used for learning and testing the migration tool")。注销后,用户运行forc migrate时若没有活跃步骤,将看到get_migration_steps_or_return!宏打印的提示信息,而非报错。
检查项四:发布前的文档收尾
破坏性版本发布前,文档工作同样不可遗漏,清单给出三个子项:
- 确保实验性功能本身已被完整记录:该功能的最终行为、用法、与旧行为的差异必须在官方文档(如 Sway Book)中有完整章节,读者无需依赖 tracking issue 就能理解新特性;
- 移除所有将功能描述为"实验性"的 Note:文档中凡是标注该功能为 experimental、并附带"将来可能变更"警示语的旁注都应删除或改写为稳定行为描述;
- 更新所有相关文档:包括 manifest 参考(
Forc.toml中experimental字段的说明)、属性参考(#[cfg]条件编译说明)、实验性功能总览 以及示例代码等,确保文档与转正后的编译器行为一致,避免遗留"开关已不存在"的过时指引。
清单背后的完整生命周期:从实验性功能到稳定特性
把上述检查项串联起来,可以还原 Sway 破坏性变更的完整工作流:
- 开发期:新特性以实验性功能形式注册于
sway-features,通过Forc.toml/ CLI / 环境变量三重开关控制,配合#[cfg(experimental_*)]条件编译在仓库内共存新旧实现; - 预发布期:在破坏性版本的前一个补丁版本中,为
forc migrate注册好该功能的全部迁移步骤(MIGRATION_STEPS),让用户提前通过show/check/run评估与执行迁移; - 发布期:按清单执行——移除编译器与 Sway 代码中的全部门控、删除按功能的测试配置与 CI 任务、关闭 tracking issue、注销迁移步骤但保留实现作为示例、完成文档收尾,随后发布破坏性版本;
- 沉淀期:旧迁移代码与
demo迁移一起作为后续破坏性变更的参考资料长期保留。
结语
docs/breaking-release-checklist.md虽是一份不足二十行的勾选清单,却是 Sway 团队管理破坏性变更的核心操作规程。它背后对应着一套可执行的工程体系:sway-features负责功能的注册与开关解析,forc-migrate负责迁移步骤的注册、校验与执行,.github/workflows/ci.yml负责实验性功能的矩阵化验证,而文档体系则保证用户始终能看到与当前编译器一致的行为说明。对希望在 Sway 生态中平稳跨版本升级的开发者而言,理解这条清单等同于理解"破坏性版本发布前,官方如何保证迁移工具、测试与文档三者就绪";对编译器维护者而言,它更是一份可以直接照着执行的发布 SOP。
相关参考文件:
- docs/breaking-release-checklist.md(本文依据的原始清单)
- sway-features/src/lib.rs(实验性功能注册与开关解析)
- docs/book/src/reference/experimental_features.md(实验性功能使用文档)
- forc-plugins/forc-migrate/src/migrations/mod.rs(迁移步骤注册表与一致性校验)
- forc-plugins/forc-migrate/src/cli/commands/check.rs 与 run.rs(check / run 实现)
- .github/workflows/ci.yml(实验性功能 CI 测试矩阵)
【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考