Skip to content

Latest commit

 

History

History
94 lines (67 loc) · 5.37 KB

File metadata and controls

94 lines (67 loc) · 5.37 KB
title tags
05. ABI编码基础
solidity
abi

WTF Solidity内部标准: 05. ABI编码基础

《WTF Solidity内部标准》教程将介绍Solidity智能合约中的存储布局,内存布局,以及ABI编码规则,帮助大家理解Solidity的内部规则。

推特:@0xAA_Science

社区:Discord微信群官网 wtf.academy

所有代码和教程开源在github: github.com/AmazingAng/WTF-Solidity-Internals


合约ABI(Application Binary Interface,应用二进制接口)规范是在以太坊生态系统中与合约交互的标准方式,包括从区块链外部和合约间的交互。这一讲,我们将介绍ABI编码基础,主要介绍静态类型的ABI编码规范。

ABI编码

合约ABI规范是在以太坊生态系统中与合约交互的标准方式,包括从区块链外部和合约间的交互。其中很重要的一项就是数据编码和解码:Solidity合约中的函数参数(calldata)和返回值(returndata)可能具有复杂的数据结构,包括结构体、数组和映射等。ABI 规范定义了如何对这些数据进行编码和解码,以便在合约之间传递和解释数据。这使得合约能够正确处理不同数据类型和数据结构,确保数据的完整性和一致性。

静态类型的ABI编码规范

我们可以把Solidity中的变量类型分为两组,静态类型和动态类型。动态类型包括:

  1. bytesstring
  2. 动态数组。
  3. 动态类型T的定长数组T[k],其中k > 0
  4. 由任意动态类型构成的元组。

其余均为静态类型。静态类型是直接编码的,而动态类型是在当前块之后的一个单独分配的位置进行编码,我们会在之后的章节中详细介绍动态类型的编码。

在ABI编码时,我们通常以32字节为一个单位来编码数据。下面,我们介绍静态类型的ABI编码规范:

  1. uint<M>: M位的无符号整数,M的取值为0256之间的可以整除8的整数,比如uint8uint32uint256uintuint256的同义词)。编码时,会在它们左侧补充若干0以使其长度成为32字节。

  2. address: 与uint160的编码方式相同。address payablecontract类型的变量也使用相同的编码方式。

  3. bool: 1表示true0表示false,编码方式与uint8的情况相同。

  4. bytes<M>:长度为M字节的字节数组,0 < M <= 32,编码时会在右侧补若干0使其长度成为32字节。

  5. 静态定长数组T[k]: T为静态类型,比如uintk为定长数组的长度,是正整数。它就像先将相同类型的k个元素分别编码,再顺序拼接到一起。

  6. 静态元组(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())并返回。下面,我们逐个分析。

  1. uint a = 1,本身就是32字节,会被编码为0000000000000000000000000000000000000000000000000000000000000001
  2. uint8 b = 2,根据规则,会在左边填充032字节,被编码为0000000000000000000000000000000000000000000000000000000000000002
  3. uint32[3] memory c = [uint32(3),4,5],静态定长数组,每个元素会单独编码,并拼接到一起。因此它会被编码为
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000004
0000000000000000000000000000000000000000000000000000000000000005
  1. bool d = true,根据规则,会在左边填充032字节,被编码为0000000000000000000000000000000000000000000000000000000000000001
  2. bytes1 e = hex"aa",定长字节数组,根据规则,会在右边填充032字节,被编码为aa00000000000000000000000000000000000000000000000000000000000000
  3. address f,与uint160的编码方式相同,会在左边填充032字节,被编码为0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c71

因此,这个函数的返回值应该是:

0x
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003
0000000000000000000000000000000000000000000000000000000000000004
0000000000000000000000000000000000000000000000000000000000000005
0000000000000000000000000000000000000000000000000000000000000001
aa00000000000000000000000000000000000000000000000000000000000000
0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c71

总结

这一讲,我们介绍了Solidity合约的ABI编码基础,尤其是静态类型的编码。合约ABI规范是在以太坊生态系统中与合约交互的标准方式,理解它非常重要。