我们很高兴地宣布 Solidity 编译器v0.8.27.
版本的发布。require 函数中自定义错误支持已添加到传统管道,编译器还包含了优化器改进(例如优化后的 IR 缓存,可通过 IR 加速编译),以及多个错误修复等!
主要特性
传统管道中 require 函数的自定义错误支持
Solidity 中的自定义错误提供了一种便捷且节省 gas 的方法来向用户解释操作失败的原因。在编译器的先前版本中,我们实现了备受期待的功能:在 require 函数中使用错误。该版本引入了一个新的重载函数——require(bool, <error>),它使用错误的签名而不是其他变体中使用的 Error(string) 来进行回退。
但是,仅 IR 管道(即通过 Yul 进行编译)支持在 require 中使用自定义错误。随着 0.8.27 版本的发布,您也可以在传统管道中使用此功能。
要详细了解此功能及其使用方法,请查看 我们之前的版本发布公告中的示例。
优化后的 IR 缓存
在调查 IR 管道的性能瓶颈时,我们意识到设计的一个方面对实际项目的性能影响远大于我们在引入该管道时所设想的。
一些背景信息:当合约在编译时需要另一个合约的字节码信息时,被访问的字节码需要作为依赖项嵌入到访问合约中。例如,当合约需要使用 new 进行部署,或访问其 .runtimeCode 或 .creationCode 时,就会发生这种情况。
在 IR 管道中,这种嵌入非常早地发生,在 Yul 代码生成期间就已经开始了。被访问合约的源代码作为 Yul 子对象包含在内,这意味着可以使用语言原语轻松访问其字节码。这确保了代码生成器的输出是自包含的,并使管道非常简单。无需链接任何外部工件,并且可以在每个阶段了解源代码的所有信息。
但是,这种设计的缺点是,每次包含依赖项时,整个管道都必须再次在该依赖项上运行。特别是,即使合约已单独进行了优化,整个优化过程也会重复。
新功能通过在 Yul 对象级别引入缓存来保持 IR 管道的简单性。由于每个 Yul 对象都是独立优化的,因此在编译字节码依赖项时可以重复使用结果。您可以在下面看到我们在一些热门项目上的基准测试结果
项目 | 0.8.26 | 0.8.27 | 加速 |
---|---|---|---|
openzeppelin | 37 秒 | 37 秒 | 0% |
uniswap-v4 | 225 秒 | 147 秒 | 42% |
eigenlayer | 1211 秒 | 674 秒 | 44% |
请注意,某些项目不受影响,而其他项目的差异则非常大。我们观察到,在每种情况下部署的生产代码实际上只有很少的字节码依赖项,并且编译速度相对较快,这证实了我们的初始假设。但是,在某些项目中,测试套件广泛使用了 new,导致大型测试合约多次进行相同的优化。在这种用例中,new 的成本无关紧要,而使用它可以使整个测试保持在 Solidity 中编写,因此它已成为 Foundry 等框架中的常见模式。由于缓存的存在,编译器现在可以有效地处理此模式。
其他说明
瞬态存储
此版本将瞬态存储变量支持引入解析器。澄清一下,此功能整体上尚未完成。
编译器现在将接受用于将某些变量标记为 transient 的语法,并允许用户生成瞬态存储布局。但是,仍然无法为使用此类变量的合约生成字节码。
我们计划在未来几个版本中逐步引入对瞬态存储的高级语言支持。特别是,下一个版本将提供对值类型瞬态状态变量的全面支持。然后,我们将扩展支持范围以涵盖更复杂的用例。
--strict-assembly 与 --yul
此版本删除了已弃用的类型化 Yul 方言,该方言只能通过 CLI 中的 --yul 选项访问。用户不应将此误解为对 Yul 支持的弃用。
请注意,此更改不会以任何方式影响 Yul 编译。一直以来,用于选择唯一常用的 Yul 方言的选项是 --strict-assembly,而不是 --yul。后者仅用于实验性的类型化方言,该方言现已弃用。
完整变更日志
语言特性
- 接受使用 transient 数据位置声明状态变量(仅解析器支持,尚未生成代码)。
- 在使用传统管道时,使 require(bool, Error) 可用。
- Yul:已放宽源位置注释的解析规则:现在允许位置组件之间的空格以及单引号代码片段。
编译器特性
- 命令行界面:添加 --transient-storage-layout 输出。
- 命令行界面:允许在汇编程序模式下使用 --asm-json 输出选项以 JSON 格式导出合约的 EVM 汇编代码。
- 命令行界面:仅请求未优化的 IR 时,不执行 IR 优化。
- 常量优化器:如果选定的 evm 版本支持,则使用 PUSH0。
- 错误报告:现在将未实现的功能正确报告为错误,而不是将其视为 bug 来处理。
- EVM:支持 EVM 版本“Prague”。
- 窥孔优化器:当支持时,显式复制 PUSH0,而不是使用 DUP1。
- 窥孔优化器:如果一个接一个地出现,则删除终止控制流的相同代码片段。
- SMTChecker:添加对一元减运算符下溢和上溢的 CHC 引擎检查。
- SMTChecker:用 cvc5 替换 CVC4 作为可能的 BMC 后端。
- 标准 JSON 接口:添加 transientStorageLayout 输出。
- 标准 JSON 接口:仅请求未优化的 IR 时,不执行 IR 优化。
- Yul:删除已弃用的类型化 Yul 方言,该方言只能通过 CLI 中的 --yul 访问。
- Yul:类型出现在非类型化 Yul 方言中现在是解析器错误。
- Yul 优化器:优化后的 IR 缓存,以加快具有字节码依赖项的合约的优化速度。
- Yul 优化器:优化器现在将一些以前无法识别的相同文字视为相同。
错误修复
- 汇编程序:修复当代码大小超过 255 时,由于不精确计算字节码中标签所需大小而导致的 ICE。
- 解析器:修复在某些情况下,当一元加运算符用作二元运算符时,错误地发出的解析器错误。
- SMTChecker:修复为 BMC 和 CHC 引擎报告验证检查数量无效的错误。
- SMTChecker:修复不变量中一元减表达式的格式。
- SMTChecker:修复在为 BMC 引擎报告已证明的目标时发生的内部编译器错误。
- SMTChecker:修复为合约或函数数组赋值时的 SMT 逻辑错误。
- 标准 JSON 接口:对于 Yul 输入,在出现警告时正确生成输出工件。
- 类型检查器:修复将嵌套元组分配给元组时的段错误。
- Yul IR 代码生成:Yul 子对象的确定性顺序。
- Yul 优化器:修复 Yul 源位置始终引用未优化的源,即使在优化的输出中也是如此。
- Yul 优化器:修复当没有错误时警告被生成两次。
- Yul 优化器:名称简化可能导致禁止的标识符以点开头和/或结尾,例如 x._ 将简化为 x.。
- Yul 解析器:修复解析非常长的位置注释时发生的段错误。
构建系统
- 更改构建系统以对某些依赖项(nlohmann-json、fmtlib 和 range-v3)使用 git 子模块。
如何安装/升级?
要升级到最新版本的 Solidity 编译器,请按照安装说明(位于我们的文档中)。您可以在此处下载 Solidity 的新版本:v0.8.27。
如果您想从源代码构建,请不要使用 GitHub 自动生成的源代码存档。
最后但并非最不重要的一点是,我们要感谢所有帮助使本次发布成为可能的贡献者!