2021 年 9 月 28 日,Harry Altman (@haltman-at) 在 Truffle 中发现了一个用户定义的值类型错误。
该错误不会影响 Solidity 合约的正确性,但使用此新功能编译的 Solidity 0.8.8 合约会不必要地浪费资源,并且可能会在工具或合约升级方面出现问题。
该错误仅存在于 Solidity 0.8.8 中,并在 0.8.9 中修复。
我们将该错误的严重程度评为“非常低”。
用户定义的值类型的存储布局
编译器没有根据短于 32 字节的类型正确计算用户定义的值类型的存储布局。它始终会为这些类型使用完整的存储槽,即使底层类型更短也是如此。0.8.8 中的用户定义的值类型应与底层类型在所有方面(存储布局除外)具有相同的表示形式。
短于 32 字节的类型如果空间足够,可以与其他值共享一个存储槽。例如
pragma solidity =0.8.8; type MyInt128 is int128; contract WastefulStorageLayout { // slot 0 MyInt128 a; // slot 1 MyInt128 b; } contract PackedStorageLayout { // slot 0 int128 a; // slot 0 int128 b; }
您可以通过运行以下命令来验证这一点solc --storage-layout Contract.sol.
影响
Solidity 试图保证合约的存储布局在不同版本之间保持一致。这使得某些类型的升级模式可以存在,这些模式可能使用不同的 Solidity 版本。由于用户定义的值类型应与底层类型完全相同,Solidity 0.8.8 为具有短用户定义的值类型作为状态变量的合约引入了不一致的存储布局。Solidity 0.8.9 版本修正了布局。从使用短用户定义的值类型的 Solidity 0.8.8 编译的合约升级到 0.8.9 以上的版本时,要格外小心。