forge-std中storage slot是什么?如何指定编号?测试编号变更失败解惑
关于Solidity存储槽(Storage Slot)与Forge
vm.store的解惑 1. 什么是Storage Slot?
以太坊合约的状态变量(比如NFT合约里的totalSupply、maxSupply这类持久化变量)都存储在区块链的「存储(Storage)」区域中。这个区域被划分为固定大小的单元——每个单元占32字节(即bytes32),每个单元就是一个存储槽(Storage Slot),槽位从0开始按顺序递增编号。
Solidity默认会按照合约中状态变量的声明顺序,依次为变量分配槽位(除非存在变量打包优化:比如多个uint128、bool这类小类型变量会被合并到同一个槽里,节省存储成本)。
2. 为什么你的代码里必须用槽位7?
在你的测试代码中,vm.store修改的是NFT合约里控制供应量上限的变量(比如totalSupply或maxSupply)所在的槽位——也就是第7个槽。当你把这个槽的值设为10000,就模拟了「已铸造数量达到上限」的状态,此时调用mintNft会触发MaxSupplyReached回滚,测试符合预期。
如果改成槽位8,你修改的是另一个无关变量的存储位置(比如合约的owner地址、某个配置参数等),此时供应量相关的变量并没有被篡改,mintNft不会触发回滚,vm.expectRevert断言失败,测试自然通不过。
3. 如何确定变量对应的存储槽?
- 查看合约变量声明顺序:如果你的NFT合约状态变量是按顺序声明的,比如:
可以按顺序数到目标变量的槽位(注意要排除变量打包合并的情况)。contract MyNFT { address public owner; // 槽位0 uint256 public maxSupply; // 槽位1 uint256 public totalSupply; // 槽位2 // ... 其他变量,直到第7个槽对应目标变量 } - 用Foundry工具验证:在测试中可以用
vm.load读取指定槽的值,确认是否对应目标变量:bytes32 slotValue = vm.load(address(nftToken), bytes32(uint256(7))); console.log(uint256(slotValue)); // 打印该槽当前值,验证是否是要修改的变量 - 查看编译后的存储布局:用
forge build编译合约时,会在out/目录的合约JSON文件中生成存储布局,里面会明确列出每个状态变量对应的槽位。
内容的提问来源于stack exchange,提问作者Santiago
相关产品推荐
相关产品推荐

