为何对长度32的动态bytes调用SSTORE结果恒为0x000...080?
问题分析与解决
问题根源
核心问题出在Yul汇编对参数的处理逻辑上:
bytes memory是动态内存数组,在汇编层面它本质是一个内存指针(指向内存中存储该数组的起始位置,Solidity里动态内存数组默认从0x80开始分配)。- 你直接写
sstore(key, val)时,存进存储的不是val里的实际数据,而是这个指针本身的值(也就是0x80),所以不管val内容是什么,sload读出来都是0x000...080。 - 换成
bytes32类型就正常,是因为它是值类型,传递给sstore的就是实际的32字节数据,而非指针。
修复代码
要把bytes memory里的实际数据存入存储,得手动跳过长度字段读取内存中的内容。因为你用abi.encodePacked生成的刚好是32字节数据,直接读取指针偏移0x20位置的内容即可:
bytes32 key = bytes32(0); bytes memory val = abi.encodePacked(bytes32(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); bytes32 result; assembly { // 跳过bytes memory的长度字段(前32字节),读取实际数据 let actualVal := mload(add(val, 0x20)) sstore(key, actualVal) result := sload(key) } // 此时result会等于预期的0xFFF...FFF result;
补充说明
- Solidity中
bytes memory的内存布局:前32字节存储数组长度,从val + 0x20开始才是实际的字节内容。 - 如果你的
bytes memory长度不是32字节,需要根据实际长度处理,但本例中abi.encodePacked(bytes32(...))刚好生成固定32字节,所以这个方法完全适用。
内容的提问来源于stack exchange,提问作者Sam Goldman
相关产品推荐
相关产品推荐

