OpenZeppelin Contracts 5.0 版本:更好的 Gas 效率,更优的代码结构。
OpenZeppelin Contracts 5.0 是自 2021 年以来的首个主要版本,团队使该库更现代并提高效率,同时保持最先进的安全实践。
作为以太坊和其他 EVM 区块链上最广泛采用的库,OpenZeppelin Contracts 5.0 版本始终致力于为开发人员提供构建安全、高效和未来可靠的智能合约系统所需的工具。随着 5.0 版本的发布,我们相信这一承诺比以往任何时候都更加坚定。
从编译器功能到较新的标准化实践,自我们上一个主要版本 Contracts 4.0 以来,智能合约开发领域发生了重大变化。Contracts 5.0 包括一套现代化的功能,提高了安全性、效率和开发人员体验。
在 5.0 版本中,我们从 ERC20、ERC721 和 ERC1155 中删除了token Hook,而是采用了一个单一的 _update
函数。这也可以在任何 mint
、transfer
或 burn
操作中进行自定义行为的重写。
作为额外的简化,Ownable 现在在构造函数中接受自定义的所有者参数,而 Governor 支持使用字节格式的签名进行投票,并通过实现 ERC-1271 支持账户抽象。
为了提高效率、简化操作和增强安全性,我们已经移除了一些函数和合约,其中一些可能会在未来版本中重新引入并提供更好的支持。在 5.0 版本中,移除的内容包括:
为了解决复杂可升级合约中存储布局变化带来的风险和麻烦,团队提出了ERC-7201:命名空间存储布局。这个方案受到了钻石存储模式的启发,但通过标准化的方式使我们的工具能够集成安全检查,同时减少潜在的安全风险。
这个命名空间存储模式在新版本中被用作一种避免升级过程中最常见且容易忽视的安全问题之一:实现版本之间的存储布局冲突。
以前,可升级合约在继承的合约之间的存储中会有一个__gap
变量,以便为升级过程中添加的新变量预留空间。但在这个新版本中,使用 ERC-7201 对存储位置进行了命名空间划分,以便在添加新变量时不会影响先前存储的变量。
通过为变量设置命名空间,每个继承的合约将保留自己的存储指针,在后续升级后可以轻松地容纳更多的值。
该库已更新至Solidity 0.8.20 版本,使我们能够引入自定义错误和显式导入,以及语言的一些小改进,如abi.encodeCall
以改善类型检查。
应用程序和钱包在过去通常依赖于从回退函数中读取普通错误字符串(例如,revert("未经授权"))来消耗错误信息。然而,现在在 OpenZeppelin Contracts 中可以使用自定义错误,遵循构建错误的标准实践。这个新增功能是受到社区的建议和ERC-6093规范的启发。
自定义错误为开发人员提供了更高效和标准化的方式来报告智能合约中的错误,还可以包括动态参数。
在 5.0 版本中,我们还引入了显式导入,以避免污染全局作用域,并使开发人员更容易跟踪导入路径。
除了对核心库的更改之外,我们还发布了Upgrades Plugins和OpenZeppelin Contracts Wizard的更新。除了升级对Hardhat的支持外,我们计划在今年晚些时候添加对 Foundry 的升级支持。
Contracts 库还与 OpenZeppelin Defender 安全平台进行了本地集成。Defender 通过提供额外的安全、性能和支持功能,扩展了开源合约标准,包括:
我们通过对整个库进行优化,平衡了可读性和效率,从而降低了部署和运行时成本。这些成本降低让前 10 个优化过函数的平均减少 9.63%,前 10 个减少的合约的平均部署成本削减 27.11%。
引入自定义错误后,库的部署成本平均降低了 12.84%。这些部署成本的降低主要是由于回滚字符串在字节码大小上的影响,这些字符串不再存储在合约字节码中,对于使用长回滚字符串(如 AccessControl)的合约,回滚字符串占据了超过 20%的空间。
存储读取是运行时中最昂贵的操作之一,5.0 通过避免可能的重复 SLOAD 操作(例如在更新的 ERC271 实现中)节省了gas。
类似地,库中使用了更多的不可变(immutable)变量,以避免这种不必要的存储读取。透明升级代理和 Beacon 代理中应用了这种模式的一些示例,现在管理员或 beacon 被存储在不可变变量中,这样每次调用这些代理时都可以节省读取操作。
Contracts 5.0 重新组织了一些最常用的数据结构和变量,以最小化存储使用,降低了读取和写入这些变量的gas成本。
这种策略的一个例子可以在更新的 Governor 提案结构中找到,它以前存储在 3 个槽中,并为了向后兼容性而添加了多个存储间隙。它的新结构只使用了 2 个槽,并且常常一起使用的变量共享同一个槽,减少了不必要的存储读取,提高了gas的使用效率。
## 灵活透明的访问管理
随着行业的发展,智能合约系统在权限和角色管理层面变得越来越强大和复杂。复杂的系统通常通过多个合约进行协调,包括多签名、DAO、时间锁和 EOA,这些已经超出了以前的访问管理机制(如 AccessControl 和 Ownable)的能力。对于这些复杂的场景,我们观察到在访问管理方面存在对单一控制源的需求。
作为去中心化协议中更复杂访问控制设置的替代方案,OpenZeppelin Contracts 5.0 引入了 AccessManager:一种现代高效的解决方案,用于跨合约进行角色管理。与单独管理每个合约不同,AccessManager 允许你从单个合约管理权限,使你的系统更易于审计和控制。
AccessManager 通过将每个合约的特定函数限制为单个角色来范围化权限。这些角色的工作方式类似于当前的 AccessControl 实现,其中可以授予多个地址一个角色或一组角色。被授予角色的每个地址可以具有即时或延迟执行的能力,使你可以直接使用时间锁定操作,而无需额外的合约。最后,现有的访问控制系统和使用 Governor 的 DAO 可以迁移到使用 AccessManager 而无需进行任何升级。实际上,我们预计这些变化将在安全开发生命周期中显着提高透明度和灵活性。
OpenZeppelin Defender 即将支持 AccessManager。如果你有兴趣在可用时进行测试,请联系我们。
OpenZeppelin Contracts 仍然保持着约 99%的单元测试覆盖率。在 5.0 版本中,我们增加了更多的模糊测试和额外的形式验证规则,包括对新的 Access Manager 实现进行形式验证。我们还对 Contracts 5.0 进行了广泛的审计。详细信息已发布在我们的Contracts Security Center上。
鉴于所涉及的范围和复杂性,围绕审计交付和审查的结构化流程是必不可少的。在准备 5.0 版本时,我们能够使用 OpenZeppelin Defender 的Audit 模块来简化审查流程,并确保所有更改都得到跟踪和有效解决。
发布候选版本于 9 月 19 日向公众介绍,漏洞赏金奖励暂时增加了 50%。我们的漏洞赏金计划仍然开放,并继续鼓励有兴趣的开发者帮助我们发现和修复潜在的漏洞。
我们能够开发和维护严格的审计实践,很大程度上要归功于社区的贡献和公共物品资金。在最近的Optimism RetroPGF Round 2中,OpenZeppelin 在工具和实用程序部分的所有提交中获得了最多的投票。
我们对参与使开源软件开发可持续和高质量的所有人表示感谢,并计划在 5.1 及以后继续保持行业领导地位。在即将发布的版本中,我们将继续强调诸如形式验证等先进的测试方法,以及与更广泛的生态系统(包括流行的开发工具和安全平台,如Hardhat、Foundry和OpenZeppelin Defender)的更强大的集成。
如果你正在启动一个新项目,OpenZeppelin Contracts v5.0.0 可用于Hardhat和 Foundry 环境,以及OpenZeppelin Wizard。现有项目可以访问我们的升级指南,我们建议使用 OpenZeppelin Defender 的代码模块来确保你的依赖项是最新的。
本翻译由 DeCert.me 协助支持, 来 DeCert 码一个未来, 支持每一位开发者构建自己的可信履历。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!