可变长度的数据,ABI 采用了一种指针和数据分离的方式进行编码。
在 Solidity 中,函数的调用数据需要根据 ABI 规范进行编码。对于可变长度的数据(例如数组和结构体),ABI 采用了一种指针和数据分离的方式进行编码。以下通过几个具体的例子来展示不同类型的参数在 ABI 中的编码方式。
contract VariableLength {
struct Example {
uint256 a;
uint256 b;
uint256 c;
}
function threeArgs(uint256 a, uint256[] calldata b, uint256 c) external {}
function threeArgsStruct(uint256 a, Example calldata b, uint256 c) external {}
function fiveArgs(uint256 a, uint256[] calldata b, uint256 c, uint256[] calldata d, uint256 e) external {}
function oneArg(uint256[] calldata a) external {}
function allVariable(uint256[] calldata a, uint256[] calldata b, uint256[] calldata c) external {}
}
function threeArgs(uint256 a, uint256[] calldata b, uint256 c) external {}
假设调用此函数,输入参数为:
编码后的 calldata 为:
0xc6f922d0
0000000000000000000000000000000000000000000000000000000000000007 // a = 7
0000000000000000000000000000000000000000000000000000000000000060 // b 的指针 = 0x60
0000000000000000000000000000000000000000000000000000000000000009 // c = 9
0000000000000000000000000000000000000000000000000000000000000003 // b 的长度 = 3
0000000000000000000000000000000000000000000000000000000000000001 // b[0] = 1
0000000000000000000000000000000000000000000000000000000000000002 // b[1] = 2
0000000000000000000000000000000000000000000000000000000000000003 // b[2] = 3
其中,7
b 的指针
9
依次放在 0x00
0x20
0x40
的内存槽中,b 的指针
是 0x60
意味着 0x60
内存槽开始存放数组 b 的相关内容。可以看到 0x60
存放了数组长度 3, 然后依次是数组内的元素。
function threeArgsStruct(uint256 a, Example calldata b, uint256 c) external {}
假设调用此函数,输入参数为:
calldata 中的内容为:
0x01e58fb4
0000000000000000000000000000000000000000000000000000000000000007 // a = 7
0000000000000000000000000000000000000000000000000000000000000001 // b.a = 1
0000000000000000000000000000000000000000000000000000000000000002 // b.b = 2
0000000000000000000000000000000000000000000000000000000000000003 // b.c = 3
0000000000000000000000000000000000000000000000000000000000000009 // c = 9
在这个例子中,b 是一个固定长度的结构体,因此可以直接依次存放各个字段的值,而无需使用指针。
function fiveArgs(uint256 a, uint256[] calldata b, uint256 c, uint256[] calldata d, uint256 e) external {}
假设调用此函数,输入参数为:
编码后的 calldata 为:
0x37701841
0000000000000000000000000000000000000000000000000000000000000005 // a = 5
000000000000000000000000000000000000000000000...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!