Solidity ABI 编码解码
ABI编码
Solidity中,ABI编码有4个函数:abi.encode, abi.encodePacked, abi.encodeWithSignature, abi.encodeWithSelector。
我们将用编码4个变量,他们的类型分别是uint256, address, string, uint256[2]:
1 | uint x = 10; |
1. abi.encode
将给定参数利用ABI规则编码。ABI被设计出来跟智能合约交互,他将每个参数转填充为32字节的数据,并拼接在一起。如果你要和合约交互,你要用的就是abi.encode。
1 | function encode() public view returns(bytes memory result) { |
编码的结果为
1 | 0x000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000 |
由于abi.encode将每个数据都填充为32字节,中间有很多0。
2. abi.encodePacked
将给定参数根据其所需最低空间编码。它类似 abi.encode,但是会把其中填充的很多0省略。比如,只用1字节来编码uint类型。当你想省空间,并且不与合约交互的时候,可以使用abi.encodePacked,例如算一些数据的hash时。
1 | function encodePacked() public view returns(bytes memory result) { |
编码的结果为
1 | 0x000000000000000000000000000000000000000000000000000000000000000a7a58c0be72be218b41c608b7fe7c5bb630736c713078414100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006 |
由于abi.encodePacked对编码进行了压缩,长度比abi.encode短很多。
3. abi.encodeWithSignature
与abi.encode功能类似,只不过第一个参数为函数签名,比如"foo(uint256,address)"。当调用其他合约的时候可以使用。
1 | function encodeWithSignature() public view returns(bytes memory result) { |
编码的结果为
1 | 0xe87082f1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000 |
等同于在abi.encode编码结果前加上了4字节的函数选择器。
4. abi.encodeWithSelector
与abi.encodeWithSignature功能类似,只不过第一个参数为函数选择器,为函数签名Keccak哈希的前4个字节。
1 | function encodeWithSelector() public view returns(bytes memory result) { |
编码的结果为
1 | 0xe87082f1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000 |
与abi.encodeWithSignature结果一样。
ABI解码
abi.decode
abi.decode用于解码abi.encode生成的二进制编码,将它还原成原本的参数。
1 | function decode(bytes memory data) public pure returns(uint dx, address daddr, string memory dname, uint[2] memory darray) { |
我们将abi.encode的二进制编码输入给decode,将解码出原来的参数