理解Solidity中的ABI编码

本文介绍了以太坊智能合约中应用程序二进制接口(ABI)编码的原理和方法。ABI是定义如何与智能合约交互的规范,文章详细讲解了函数签名、静态类型和动态类型的编码方式,以及abi.encode, abi.encodeWithSignature等方法的使用,帮助读者理解智能合约与外部世界进行数据交换, 需要将函数签名和参数转换成EVM可以识别的格式。

当与以太坊区块链上的智能合约交互时,理解数据是如何编码并在合约和外部世界之间传递的至关重要。这就是应用程序二进制接口(ABI)发挥作用的地方。在本文中,我们将深入探讨Solidity中ABI编码的细节,并探索它在底层是如何工作的。

什么是ABI?

ABI是一个规范,定义了如何与智能合约交互。它提供了关于合约的公共和外部函数的信息,以及每个函数接受的参数的数量和类型。当我们想要调用合约中的一个函数时,我们会编写像function(arguments)这样的表达式。然而,以太坊虚拟机(EVM)不能直接理解这样的表达式。相反,我们需要发送一个根据合约的ABI编码的二进制表达式。

函数签名

Solidity中的每个函数都有一个唯一的签名,它是通过函数Keccak256哈希的前4个字节以及它的参数类型计算出来的。

Keccak256是一个密码学哈希函数,它接受任何输入数据并返回一个固定大小的输出(32字节)。生成的哈希是一个64个字符的十六进制字符串,其中每个字节由2个十六进制数字表示。

例如,函数report(address,bytes,bytes[])的哈希是c0965dc3b09190a0490c5d16aaccc5683a8981e70f5627ad4c73c63b5fd798bf。这个哈希的前4个字节(c0965dc3)作为函数签名。

因此,ABI编码旨在将函数签名及其参数编码成可以传递给EVM的格式。

让我们记住发送到EVM以执行函数report(address,bytes,bytes[])的payload:c0965dc3...000007。前4个字节正好是函数签名。在签名之后,我们有32个字节代表函数参数。

ABI 编码

ABI编码是将函数签名和参数转换成可以传递给EVM的格式的过程。

编码的复杂性取决于参数的数量和类型。虽然编码整数很简单,但编码字符串和数组可能更复杂。

Solidity提供了一个名为abi的全局变量,它有几种用于编码和解码函数以及参数的方法。让我们来探索其中的一些方法。

abi协议规范可以在这里找到

abi.encode

abi.encode被设计用于大多数静态类型的编码。字节的填充由被编码的底层Solidity类型决定。例如:

  • address和其他小于32字节的静态类型(例如,uint8)在左侧用零填充。例如:
abi.encode(0xe592427a0aece92de3edee1f18e0157c05861564)
= 0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
  • 固定大小的字节值(例如,bytes4bytes8)在右侧用零填充。像这样:
abi.encode(0xabcdef12)
= 0xabcdef1200000000000000000000000000000000000000000000000000000000

动态类型(如字符串、字节和数组)由于其可变大小,需要一种更为细致的方法。动态类型的编码格式包括:

  1. 偏移量(Offset):第一个32字节的字指示数据开始的字节索引。
  2. 长度(Length):第二个32字节的字指示数据的长度,该长度在不同的动态类型之间变化。
  3. 数据(Data):实际数据封装在一系列32字节的字中,并遵守静态类型的填充规则。

以下是"hello world"的动态类型编码的演示


// 上面的函数将返回以下原始字节值。
0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000

// 我们可以将其拆分为32字节长的字来获得:
0x0000000000000000000000000000000000000000000000000000000000000020  // 偏移量
  000000000000000000000000000000000000000000000000000000000000000b  // 长度
  48656c6c6f20576f726c64000000000000000000000000000000000000000000  // 字符串

abi.encodeWithSignature

当在EVM中调用一个函数时,payload的前四个字节代表函数的签名。abi.encodeWithSignature方法允许将函数的参数与其签名一起编码。

abi.encodePacked

abi.encodePacked用于压缩编码,其中参数被编码为仅占用它们所需的尺寸。

使用abi.encodePacked,参数被编码为仅占用它们所需的尺寸。这种编码与EVM期望接收函数的方式不兼容,但它在某些情况下可能有用。

在Solidity中进行压缩编码时,以下ABI限制不再强制执行:

  • 动态类型(例如,字符串、数组等)完全按照它们的方式表示,没有任何偏移量或长度信息。

  • 零填充不适用于短于32字节的静态类型(例如,uint8,bytes4等)。

更多规范请参见此处

但是,值得注意的是,在未来的Solidity版本中,abi.encodePacked正在考虑弃用。

结论

理解ABI编码对于在Solidity中与智能合约进行交互至关重要。通过掌握函数签名,静态和动态类型编码以及abi变量提供的各种编码方法的概念,你将有能力处理合约与外部世界之间的数据交换。

  • 原文链接: extremelysunnyyk.medium....
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Yong kang Chia
Yong kang Chia
江湖只有他的大名,没有他的介绍。