## 0x00: 介绍 这周,Solidity发布了新的版本——0.8.29。新的特点可分为**语言层面**和**编译器层面**。 对于语言层面新特点,允许将合约的存储定位到任意位置。本篇文章会来讲讲这个,并且用代码进行演示。 至于编译器的新特点,可自行查看官方[blog](https://soliditylang.org/blog/2025/03/12/solidity-0.8.29-release-announcement/)。 <br> 先来看看,定义合约存储位置的语法: ```solidity contract C layout at 2**255 - 42 { uint x; } ``` `layout at 2**255 - 42`,即把该合约存储位置设为了从**2\*\*255 - 42**开始。注意,目前只能用**字面表达式**,而无法使用变量来设置。 > 点击[这里](https://docs.soliditylang.org/en/v0.8.29/contracts.html#custom-storage-layout)查看自定义存储布局的官方文档描述。 <br> ## 0x01:初步测试 随着Solidity发布新版本,remix也是很快地支持了0.8.29版本。下面来编写个demo试试这个特点。 ```solidity //SPDX-License-Identifier:MIT pragma solidity 0.8.29; contract Demo layout at 0x666 { // 设到0x666 uint256 public varA; function getVarASlot() public pure returns(uint256 slot) { assembly { slot := varA.slot // 获取varA的slot位置 } } } ``` <br> 将编译器设为0.8.29版本,然后点击编译。 ![image-20250313214746226](https://hackmd.io/_uploads/BJJlxdenJx.png) <br> 编译完成后进行部署,然后调用`getVarASlot()`,得到的结果为1638,也即0x666。可见,变量确实是从我们设定的位置开始存储。 ![image-20250313214836396](https://hackmd.io/_uploads/By-ZeOl3kg.png) <br> ## 0x02:继承测试 下面接着编写个DemoParent合约来试试继承时的效果。 ```solidity //SPDX-License-Identifier:MIT pragma solidity 0.8.29; contract DemoParent layout at 0x888 { uint256 public varB; } ``` <br> 在Demo合约继承DemoParent合约时,很遗憾的发生了报错警告:**不能继承一个自定义存储布局的合约**。 ![image-20250313215920166](https://hackmd.io/_uploads/BkE7x_xh1l.png) <br> 接着,我去掉`layout at 0x888`,报错也随之消失。目前DemoParent为: ```solidity //SPDX-License-Identifier:MIT pragma solidity 0.8.29; contract DemoParent { uint256 public varB; } ``` <br> 我想接着测试,看看Demo在继承DemoParent时,Demo的自定义存储布局会不会对父合约起作用。据此,我在Demo合约中编写了个获取`varB`变量slot位置的函数: ```solidity //SPDX-License-Identifier:MIT pragma solidity 0.8.29; import {DemoParent} from "./DemoParent.sol"; contract Demo layout at 0x666 is DemoParent{ uint256 public varA; function getVarASlot() public pure returns(uint256 slot) { assembly { slot := varA.slot } } function getVarBSolt() public pure returns(uint256 slot) { assembly { slot := varB.slot } } } ``` <br> 编译、部署、执行`getVarBSolt()`函数,从结果来看是会对父合约起作用的: ![image-20250313220647060](https://hackmd.io/_uploads/Bk9Hedx3kx.png) <br> ## 0x03:个人想法 官方表明,支持这一语言特性是为了辅助即将到来的**Pectra**升级中的**EIP-7702**提案。不过我第一眼想到的是EIP-7201规范,该规范用于可升级代理模式中避免升级后的存储冲突。 ![image-20250313222606360](https://hackmd.io/_uploads/Hkc8xOe31g.png) <br> 新的特点刚好可以简化代码的编写。不过目前的自定义存储布局,就像上面测试那样,父合约无法与子合约分开定义,估计还是难以满足需求。 至于下一步,官方说会实现使用常数(constants)来定义存储布局,我大概理解成是可以在构造函数执行时,通过传入参数来进行定义。 值得期待……