Solidity 0.8.35 版本发布公告

Solidity v0.8.35 发布,新增 erc7201 内置函数,用于计算 ERC-7201 命名空间存储布局的基础槽位,这是首个编译常量内置函数。

由 Solidity 团队发布于 2026 年 4 月 29 日

发布

我们激动地宣布 Solidity 编译器 v0.8.35 的发布!

此版本引入了一个新的内建函数 erc7201,用于从命名空间字符串计算 ERC-7201 命名空间存储布局的基础槽位。 同时正式规定了实验性功能向用户公开的方式:开发中的功能现在需要一个新的顶层 --experimental 标志才能启用,并附带文档化的生命周期和当前被视为实验性的功能的规范列表。 在这个新生命周期下交付的第一个主要代码生成功能是实验性的 SSA 形式控制流图(SSA CFG)代码生成器,我们期望它能成为解决 IR 流水线中编译时间过长和栈过深错误的长期方案。 在错误修复方面,IR 流水线在使用 --revert-strings strip 编译时,不再过度剥离自定义错误。

此版本还继续了从 0.8.31 开始的 0.9.0 弃用工作,这次则是对那些将在 0.9.0 中提升为关键字的标识符发出警告。

其中一些功能在我们三月份分享的 v0.8.35-pre.1 预发布版中已经可用。

值得注意的功能与变更

erc7201 编译期内建函数

Solidity 0.8.35 引入了一个新的内建函数:

function erc7201(string memory id) returns (uint)

它使用 ERC-7201 中定义的公式计算命名空间字符串的基础存储槽位,等价于 keccak256(keccak256(id) - 1) & ~0xff。 ERC-7201 正式化了将合约状态放置在哈希命名空间之后的做法,以避免在基于代理和钻石风格的可升级模式中出现存储冲突。

该内建函数与 0.8.29 引入并在 0.8.31 扩展的存储布局指定器自然搭配:

contract MyContract layout at erc7201("openzeppelin.storage.MyContract") {
    uint256 x;
    uint256 y;
}

erc7201 的特殊之处在于,它是该语言中第一个编译期内建函数。 到目前为止,Solidity 的编译期求值器只处理有理数字面量的算术。 现有的内建函数如 keccak256 确实会在优化阶段被代码生成器折叠;你能得到 Gas 节省,但无法获得在布局指定器等编译期上下文中使用它所带来的类型系统好处。 erc7201 是第一个结果可以在任何需要编译期表达式的地方使用的内建函数:作为 layout at 的基础槽位,或作为数组长度。 这直接解决了我们在 0.8.31 版本中指出的限制之一,我们期望随着努力构建更强大的编译期求值器,会有更多这样的内建函数。

正式化实验性功能流程

过去的版本发布了许多开发中的功能,这些功能可以通过临时性的 CLI 标志和 pragma 实验性指令混合启用。 用户没有一致的方式来意识到自己正在启用不稳定的功能,元数据信号也很零散。

在 0.8.35 中,我们正式化了这一流程。 完整流程在新的实验模式文档页面中描述;以下是面向用户的关键变化。

--experimental 标志

使用任何实验性功能现在都需要新的顶层 --experimental 标志,或在 Standard JSON 输入中对应的 boolean 设置 settings.experimental 字段。 --experimental 是一个总开关:它本身不启用任何特定功能,但任何按功能划分的标志或 pragma 都必须在其支持下才能被接受。 当前实验性功能的列表、它们的 ID 以及驱动每个功能的标志或 pragma,都在实验模式文档页面中维护。

现在,不使用 --experimental 而使用其中任何一个都会导致硬错误。 那些之前直接传递受影响标志的用户现在需要添加 --experimental(或在 JSON 输入中设置 settings.experimental: true)才能保持构建正常。 这不是向后兼容性的破坏:实验性功能一直都不在我们的兼容性保证范围内。 新的变化是在用户界面上明确这一点,确保没有人无意中启用实验性功能:实验性功能没有任何稳定性保证,即使在编译器的非破坏性版本中也可能以破坏性方式更改

记录在元数据中

合约是否在启用实验性模式的情况下编译,现在会记录在 JSON 和 CBOR 元数据中。 CBOR 中的 experimental 字段之前仅指示源中的实验性 pragma,现在已扩展以涵盖这一点。 这也填补了一个已知的空白:之前针对未发布的 EVM 版本编译会产生实验性字节码,但不会标记该标志。

实验性 SSA CFG 代码生成器

Solidity 0.8.35 为 IR 流水线发布了一个实验性的新 EVM 后端。 它从程序的 SSA 形式控制流图(每个函数一个“SSA CFG”)生成字节码,并预先计算好栈布局,后端会调整 EVM 栈以匹配。

我们构建它的原因:IR 流水线有两个长期存在的痛点——栈过深错误和编译速度慢,而基于 SSA 的后端可以解决这两个问题。 栈过深在我们的 2025 年开发者调查仍然是报告最多的反复出现的问题,而且 IR 编译长期以来明显比 evmasm 流水线慢。 当前的 Yul 到 EVM 代码转换依赖启发式方法,在处理深层嵌套表达式和复杂控制流时很吃力,相同的算法问题也导致了较长的编译时间。 基于 SSA 的后端为栈调度和编译性能提供了更强的基础,我们将其视为解决这两个问题的现实长期路径。

如果你想深入了解 SSA CFG 的工作原理,我们在 Solidity Summit 的演讲中对此进行了介绍。

在命令行中使用 --experimental --via-ssa-cfg 启用代码生成器,或在 Standard JSON 中设置 settings.experimental: true 并同时设置 settings.viaSSACFG: true。 两者都隐含了 --via-ir。

这是一个早期的实验版本。几个部分尚未就绪:

  • 栈到内存的溢出(spilling)尚未移植到 SSA 后端。
  • 特定于 SSA CFG 的优化器阶段仍在开发中。
  • 作为长期动机之一的编译性能工作尚未落地。
  • 栈调度器耗尽的情况目前会表现为内部编译器错误,而不是优雅的“栈过深”或溢出诊断。

在每次 PR 中,该代码生成器都会针对完整的外部合约语义测试套件进行测试,但它还不是 --via-ir 的默认选项,仅凭 Gas 数据不足以将其升级。 在成为默认选项之前,我们预计会经过审查、模糊测试,可能还有外部审计。

根据新的实验性政策,只有影响 SSA CFG 代码生成的主要更改才会记录在更新日志中。

即将到来的 0.9.0 关键字的弃用警告

继续从 0.8.31 开始的弃用工作,此版本对计划在 0.9.0 中提升为关键字的标识符添加了警告。 0.8.31 的弃用是关于要移除的功能,而这一批是关于要占用的名称。

使用 at、error、layout、leave、super、this 或 transient 的 Solidity 声明现在会发出警告。

在 Yul(独立或内联汇编)中,leave 将成为 Yul 关键字,而 basefee、blobbasefee、blobhash、clz、mcopy、memoryguard、prevrandao、tload 和 tstore 将成为 Yul 保留标识符。 后者都是 Yul 内建函数,我们通常将其保留为保留标识符;不断增长的例外列表是异常长的 0.8.x 发布周期的一个特点,因为我们的向后兼容性政策使它们一直保留到 0.9.0。

这些是警告,不是错误。现有代码仍然可以编译;在 0.9.0 将这些警告变为错误之前,你有一个时间窗口来重命名受影响的声明。

--revert-strings strip 与自定义错误

--revert-strings strip(Standard JSON 中的 revertStrings: "strip")是一个节省 Gas 的选项:没有回退原因字符串的字节码更小,且回退仍然发生。 隐含的假设是返回数据(returndata)是向用户传递友好消息的一种方式,而不是另一个合约应该依赖的结构化数据。

require(condition, CustomError(...)) 使情况复杂化,因为自定义错误编码了结构化数据。 直到 0.8.35,IR 流水线(--via-ir)一直在剥离 require 的自定义错误参数以及字符串,因此失败的 require 会以空错误数据回退,而不是编码的自定义错误。 evmasm 流水线的行为不同。 这里的错误是两个流水线之间的不一致:原则上可以通过任一方式修复,我们选择保留自定义错误,而不是将 --revert-strings strip 扩展到第三种含义。

这仅影响 require(),而不影响带有自定义错误的普通 revert 语句,并且仅影响 IR 流水线。 该问题自 require(bool, error) 在 0.8.26 引入时就存在,并在 0.8.35 中修复。

ethdebug 输出重组

此版本重组了 ethdebug 输出选择,使其更细化,并与其他输出的暴露方式保持一致。 --ethdebug 和 --ethdebug-runtime 被替换为 --ethdebug-resources、--ethdebug-compilation、--ethdebug-program 和 --ethdebug-program-runtime,在 Standard JSON 中有对应的键。 ethdebug 输出不再强制进行完整的二进制编译,且 ethdebug 仍然是实验性的,现在像其他实验性功能一样需要 --experimental 标志。

完整更新日志

语言特性

  • 通用:添加一个内建函数,使用 ERC-7201 的 erc7201 公式计算存储命名空间的基础槽位。
  • 名称解析器:对选定的未来将提升为 Solidity 或 Yul 关键字的标识符发出警告(at、error、layout、leave、super、transient、this)。
  • Yul 分析器:对选定的未来将提升为 Yul 关键字和保留标识符的标识符发出警告(basefee、blobbasefee、blobhash、clz、leave、memoryguard、mcopy、prevrandao、tload、tstore)。

编译器特性

  • 命令行界面:禁止选择已弃用的汇编输入模式,该模式之前只能通过 --assemble 访问,而不是将其视为等同于 --strict-assembly。
  • 命令行界面:引入启用实验性模式所需的 --experimental 标志。
  • 命令行界面:将实验性的 --ethdebug 和 --ethdebug-runtime 输出替换为更细粒度的 --ethdebug-resources、--ethdebug-compilation、--ethdebug-program 和 --ethdebug-program-runtime。生成 ethdebug/format/info/resources 不再强制进行完整的二进制编译。
  • EVM:引入实验性的 EVM 版本 @future。
  • 通用:改进整个编译器实现中健全性检查的性能。
  • 通用:引入 SSA CFG 代码生成器(实验性)。
  • 通用:将现有的实验性功能(generic-solidity、lsp、ethdebug、eof、evm、ast-import、evmasm-import、ir-ast、ssa-cfg)限制在实验性模式下。
  • 元数据:将实验性模式的状态存储在 JSON 和 CBOR 元数据中。在 CBOR 中,这扩大了现有 experimental 字段的含义,该字段以前仅指示源中某些实验性 pragma 的存在。
  • 标准 JSON 接口:引入启用实验性模式所需的 settings.experimental 设置。
  • 标准 JSON 接口:将实验性的顶层 ethdebug 输出替换为 ethdebug.resources 和 ethdebug.compilation。将 ethdebug 输出与二进制编译解耦,以便请求 ethdebug/format/info/resources 模式工件不会触发字节码生成。
  • Yul 优化器:改进控制流副作用收集器和函数引用解析器的性能。

错误修复

  • Yul:修复了包含双引号和转义序列的 Yul 对象名称的序列化错误,该错误导致输出无法被解析为有效的 Yul。
  • Yul EVM 代码转换:通过修复 BFS 去重问题来改进栈调度器性能。
  • Yul IR 代码生成:当通过 --revert-strings strip 选择剥离回退字符串时,保留 require 的自定义错误参数。

如何安装/升级?

要升级到新版本的 Solidity 编译器,请遵循我们的文档中的安装指南。 你可以从 GitHub 下载此版本:v0.8.35

如果你想从源代码构建,请不要使用 GitHub 自动生成的源代码归档。 请改用 solidity_0.8.35.tar.gz 源码压缩包 或通过 git 检出 v0.8.35 标签。

最后但同样重要的是,我们要衷心感谢所有为此次发布做出贡献的贡献者!

  • 原文链接: soliditylang.org/blog/20...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
SolidityLang
SolidityLang
https://soliditylang.org/