abi编码的详解
1.abi.encode
abi.encode 将它的每个参数填充为32字节【32 * 8 =256位】(1byte = 8bit)的数据,并拼接在一起。
注:如果要和合约交互,使用的是abi.encode(实践操作)
1.1 abi.encode编码演示
定义的变量:
1 | uint8 num1 = 1; |
代码1:
num1是uint8类型,占用1个字节
1 | function testABIEncode1() external view returns(bytes memory reslut) { |
代码2:
num2是uint256类型,占用32个字节
1 | function testABIEncode2() external view returns(bytes memory reslut) { |
看运行结果:
由运行结果 比较num1
和num2
的编码值可知,不管参数的数据类型是什么,它都将参数填充为32位。所以这两个函数的编码结果相同。
1.2 abi.encode 与合约交互 —- 以create2为例
create2 的使用请移步 ===》
【abi.encode】
通过 abi.encode
对要部署合约的字节码和代传参数(id = 1, name = “biyou”)进行“非紧”打包:
1 | // 非紧打包 -- 涉及了合约构造函数的参数 |
运行结果的部分截图:
将获取的bytecode的值,放入create2Address
函数中,传入盐salt(biyou),计算 Student
合约的地址
create2Address
函数代码:
1 | function create2Address(bytes memory bycode,string memory salt) external view returns(address result){ |
运行结果:
再将获取的地址通过remix上的At Address
获取合约,并调用其中的函数检验结果:
At Address:
验证结果(正确):
【abi.encodePacked】
通过 abi.encodePacked
对要部署合约的字节码和代传参数(id = 1, name = “biyou”)进行“非紧”打包:
1 | // 紧打包 |
运行结果的部分截图:
将获取的bytecode的值,放入create2Address
函数中,传入盐salt(biyou),计算 Student
合约的地址
create2Address
函数同上
运行结果:
再将获取的地址通过remix上的At Address
获取合约,并调用其中的函数检验结果:
At Address:
运行结果(出错):
2. abi.encodePacked
2.1 编码演示
将给定参数根据其所需
最低空间编码
。类似于abi.encode
,但是会把其中填充的很多0省略。比如,只用1字节来编码uint类型。当你想省空间,并且不与合约交互的时候,可以使用abi.encodePacked
,例如算一些数据 的hash时。
最低空间编码(个人理解)
: 因为在以太坊EVM中的ABI,默认给每个属性(字段)赋予一个32
字节(32 * 8 = 256位)的长度(不足部分被0填充), 实际占用长度取决于属性的类型。整型:
1 >uint8 num = 1; // 这个占用8bit,即一个字节,前面将填充31 * 8 个零,又因为在以太坊中数据一般格式为16进制,16进制数的一位占四个 xxxx(x是0或1) 例: 0xff = 11111111这样前面显示的0的个数为 31 * 8 / 4 = 62个(uint8 num = 1,本身表示为:0x01)
所以使用abi.encodePacked打包,将会是保留uint8本身的长度(8位)即1字节即0x01,
如图:
1 >uint256 num2 = 1;//占用 256位,即 0x0000000000000000000000000000000000000000000000000000000000000001,因为num2声明为uint256明确指明了占用256位,所以EVM会给num2分配的最低空间为 256位所以使用abi.encodePacked打包,将会是保留uint256本身的长度(256位)即32字节
如图:
bytesn(n的范围是[1,32])类型:和uint类型类似 bytes1 ==> uint8
关于 bytes家族移步==》
string类型:
将字符串转为bytes类型之后实际有多长就保留多长
字符串转bytes代码:
1
2
3 function stingConvertBytes(string memory _str) external pure returns(bytes memory result){
result = abi.encodePacked(_str);
}
address类型:
因为address是160位的,所以只保留160位即可
定义的变量:
1 | uint8 num1 = 1; |
代码1:
num1是uint8类型,占用1个字节
num2是uint256类型,占用32个字节
_addr是address类型,占用20个字节
name是string类型,占用字节数取决于实际情况长度
bs1是bytes1类型,占用1个字节
1 | function testABIEncodePacked1() external view returns(bytes memory reslut) { |
结果:
代码2:
``num1是uint8类型,占用1个字节`
num2是uint256类型,占用32个字节
_addr是address类型,占用20个字节
name是string类型,占用字节数取决于实际情况长度
bs1是bytes1类型,占用1个字节
1 | function testABIEncodePacked2() external view returns(bytes memory reslut) { |
看运行结果:
3. 总结
不需要和其他合约交互的时候大多选择 abi.encodePacked
的打包方式,包括签名操作什么的
需要与其他合约进行交互的则选择abi.encode
的打包方式—其他的合约交互正在学习