Solidity中ENS解析器bytes转address的div(exp(256,12))作用解析
Solidity bytes memory转address的汇编逻辑差异说明
首先明确Solidity bytes memory 类型的内存布局规则:
- 内存中
bytes的起始位置开始,前32字节存储该bytes的实际长度 - 从起始位置偏移32字节的位置开始,才是bytes存储的真实内容
- EVM的
mload(op)操作会从传入的内存地址op开始,连续读取32字节的数据,返回一个uint256类型的值
原有实现的问题
你之前使用的转换代码存在偏移计算错误:
function bytesToAddress(bytes memory byte) public pure returns (address addr) { assembly { addr := mload(add(byte, 20)) } }
add(byte,20)定位到的是bytes起始位置后20字节的内存点,这个位置还处于存储长度的前32字节区间内,mload读取的32字节会包含长度字段的后12字节+真实内容的前20字节,读出来的值和实际地址完全不匹配,属于错误实现。
ENS公共解析器实现的逻辑拆解
ENS的实现首先通过require(b.length == 20)做了前置校验,保证输入的bytes长度刚好和地址长度(20字节)一致,避免长度异常导致的错误转换,内联汇编部分逐段逻辑如下:
assembly { a := div(mload(add(b, 32)), exp(256, 12)) }
add(b,32):跳过bytes开头32字节的长度字段,定位到真实内容的起始内存地址mload(add(b,32)):从内容起始位读取连续32字节。因为输入的bytes只有20字节长,这32字节里前20字节是我们需要的真实地址值,后12字节是该内存段后面的残留脏数据(不属于当前bytes变量的内容),直接把这个值转成地址会把脏数据也带进去,得到错误结果。div(..., exp(256,12)):exp(256,12)等价于2^(8*12) = 2^96,无符号整数除以2^96的效果等同于把数值逻辑右移96位,刚好把后面12字节的脏数据全部移出,剩下的高20位就是正确的地址值,最终赋值给address payable类型的返回值。
补充:新版本Solidity(0.5+)已经可以不用汇编直接做类型转换,写法为
address(uint160(bytes20(b))),编译器会自动处理内存偏移和截断逻辑,安全性更高。
内容的提问来源于stack exchange,提问作者苍苍张
相关产品推荐
相关产品推荐

