title | tags | ||
---|---|---|---|
05. ABI编码基础 |
|
《WTF Solidity内部标准》教程将介绍Solidity智能合约中的存储布局,内存布局,以及ABI编码规则,帮助大家理解Solidity的内部规则。
所有代码和教程开源在github: github.com/AmazingAng/WTF-Solidity-Internals
合约ABI(Application Binary Interface,应用二进制接口)规范是在以太坊生态系统中与合约交互的标准方式,包括从区块链外部和合约间的交互。这一讲,我们将介绍ABI编码基础,主要介绍静态类型的ABI编码规范。
合约ABI规范是在以太坊生态系统中与合约交互的标准方式,包括从区块链外部和合约间的交互。其中很重要的一项就是数据编码和解码:Solidity合约中的函数参数(calldata
)和返回值(returndata
)可能具有复杂的数据结构,包括结构体、数组和映射等。ABI 规范定义了如何对这些数据进行编码和解码,以便在合约之间传递和解释数据。这使得合约能够正确处理不同数据类型和数据结构,确保数据的完整性和一致性。
我们可以把Solidity中的变量类型分为两组,静态类型和动态类型。动态类型包括:
bytes
和string
。- 动态数组。
- 动态类型
T
的定长数组T[k]
,其中k > 0
。 - 由任意动态类型构成的元组。
其余均为静态类型。静态类型是直接编码的,而动态类型是在当前块之后的一个单独分配的位置进行编码,我们会在之后的章节中详细介绍动态类型的编码。
在ABI编码时,我们通常以32
字节为一个单位来编码数据。下面,我们介绍静态类型的ABI编码规范:
-
uint<M>
:M
位的无符号整数,M
的取值为0
到256
之间的可以整除8的整数,比如uint8
,uint32
,uint256
(uint
是uint256
的同义词)。编码时,会在它们左侧补充若干0
以使其长度成为32
字节。 -
address
: 与uint160
的编码方式相同。address payable
和contract
类型的变量也使用相同的编码方式。 -
bool
:1
表示true
,0
表示false
,编码方式与uint8
的情况相同。 -
bytes<M>
:长度为M
字节的字节数组,0 < M <= 32
,编码时会在右侧补若干0
使其长度成为32
字节。 -
静态定长数组
T[k]
:T
为静态类型,比如uint
,k
为定长数组的长度,是正整数。它就像先将相同类型的k
个元素分别编码,再顺序拼接到一起。 -
静态元组
(T1,...,Tk)
:T1,...,Tk
均为静态类型,它先将k
个元素分别编码,再顺序拼接到一起。
function testAbiEncode() public pure returns (bytes memory){
uint a = 1;
uint8 b = 2;
uint32[3] memory c = [uint32(3),4,5];
bool d = true;
bytes1 e = hex"aa";
address f = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
return abi.encode(a, b, c, d, e, f);
}
在testAbiEncode()
函数中,我们将6
个类型不同的变量进行ABI编码(使用abi.encode()
)并返回。下面,我们逐个分析。
uint a = 1
,本身就是32
字节,会被编码为0000000000000000000000000000000000000000000000000000000000000001
。uint8 b = 2
,根据规则,会在左边填充0
至32
字节,被编码为0000000000000000000000000000000000000000000000000000000000000002
。uint32[3] memory c = [uint32(3),4,5]
,静态定长数组,每个元素会单独编码,并拼接到一起。因此它会被编码为
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000004
0000000000000000000000000000000000000000000000000000000000000005
bool d = true
,根据规则,会在左边填充0
至32
字节,被编码为0000000000000000000000000000000000000000000000000000000000000001
。bytes1 e = hex"aa"
,定长字节数组,根据规则,会在右边填充0
至32
字节,被编码为aa00000000000000000000000000000000000000000000000000000000000000
address f
,与uint160
的编码方式相同,会在左边填充0
至32
字节,被编码为0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c71
。
因此,这个函数的返回值应该是:
0x
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000004
0000000000000000000000000000000000000000000000000000000000000005
0000000000000000000000000000000000000000000000000000000000000001
aa00000000000000000000000000000000000000000000000000000000000000
0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c71
这一讲,我们介绍了Solidity合约的ABI编码基础,尤其是静态类型的编码。合约ABI规范是在以太坊生态系统中与合约交互的标准方式,理解它非常重要。