title | tags | ||
---|---|---|---|
08. calldata/returndata的ABI编码 |
|
《WTF Solidity内部标准》教程将介绍Solidity智能合约中的存储布局,内存布局,以及ABI编码规则,帮助大家理解Solidity的内部规则。
所有代码和教程开源在github: github.com/AmazingAng/WTF-Solidity-Internals
这一讲,我们将介绍Solidity的函数调用calldata
和返回值returndata
的ABI编码规则。
当我们调用函数时,我们需要为要调用的函数名以及参数进行ABI编码。对于参数a_1, ..., a_n
的函数f
的调用会被编码为:
function_selector(f) e((a_1, ..., a_n))
其中function_selector(f)
为函数的选择器(函数签名的Keccak-256
哈希值的前4
字节),(a_1, ..., a_n)
为参数组成的元组,e(x)
为变量x
的ABI编码。
举个简单的例子:
function testCalldata(uint256 x, bool y) public pure{
}
当我们调用上面的testCalldata()
函数,参数为99
(也就是0x63
)和true
时,会如何编码呢?
首先,我们需要计算这个函数的函数选择器,为0xb3b1391c
。如果你不了解函数选择器,可以阅读WTF Solidity教程第29讲。
接下来我们需要编码(x, y)
。由于x
和y
都是静态类型,这个元组也是静态类型,直接编码就可以。
因此,calldata
的编码为:
0xb3b1391c
0000000000000000000000000000000000000000000000000000000000000063
0000000000000000000000000000000000000000000000000000000000000001
当函数返回时,我们需要对返回值进行编码。返回值a_1, ..., a_n
会被被编码为:
e((a_1, ..., a_n))
举个简单的例子:
function testReturndata() public pure returns(uint x, bool y){
x = 99;
y = true;
}
当我们调用上面的testReturndata()
函数,返回值是如何编码的?
其实很简单,返回值的编码就是e((x, y))
,也就是上一节calldata
编码去掉函数选择器的部分:
0x
0000000000000000000000000000000000000000000000000000000000000063
0000000000000000000000000000000000000000000000000000000000000001
这一讲,我们介绍了Solidity合约的ABI编码公式,有了它,再复杂的编码也不怕。它的核心思想是使用递归的方法把复杂类型的编码转换成简单类型的编码。