本文介绍了以太坊智能合约中应用程序二进制接口(ABI)编码的原理和方法。ABI是定义如何与智能合约交互的规范,文章详细讲解了函数签名、静态类型和动态类型的编码方式,以及abi.encode, abi.encodeWithSignature等方法的使用,帮助读者理解智能合约与外部世界进行数据交换, 需要将函数签名和参数转换成EVM可以识别的格式。
当与以太坊区块链上的智能合约交互时,理解数据是如何编码并在合约和外部世界之间传递的至关重要。这就是应用程序二进制接口(ABI)发挥作用的地方。在本文中,我们将深入探讨Solidity中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编码是将函数签名和参数转换成可以传递给EVM的格式的过程。
编码的复杂性取决于参数的数量和类型。虽然编码整数很简单,但编码字符串和数组可能更复杂。
Solidity提供了一个名为abi
的全局变量,它有几种用于编码和解码函数以及参数的方法。让我们来探索其中的一些方法。
abi协议规范可以在这里找到
abi.encode
被设计用于大多数静态类型的编码。字节的填充由被编码的底层Solidity类型决定。例如:
address
和其他小于32字节的静态类型(例如,uint8
)在左侧用零填充。例如:abi.encode(0xe592427a0aece92de3edee1f18e0157c05861564)
= 0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
bytes4
,bytes8
)在右侧用零填充。像这样:abi.encode(0xabcdef12)
= 0xabcdef1200000000000000000000000000000000000000000000000000000000
动态类型(如字符串、字节和数组)由于其可变大小,需要一种更为细致的方法。动态类型的编码格式包括:
以下是"hello world"
的动态类型编码的演示
// 上面的函数将返回以下原始字节值。
0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
// 我们可以将其拆分为32字节长的字来获得:
0x0000000000000000000000000000000000000000000000000000000000000020 // 偏移量
000000000000000000000000000000000000000000000000000000000000000b // 长度
48656c6c6f20576f726c64000000000000000000000000000000000000000000 // 字符串
当在EVM中调用一个函数时,payload的前四个字节代表函数的签名。abi.encodeWithSignature
方法允许将函数的参数与其签名一起编码。
abi.encodePacked
用于压缩编码,其中参数被编码为仅占用它们所需的尺寸。
使用abi.encodePacked
,参数被编码为仅占用它们所需的尺寸。这种编码与EVM期望接收函数的方式不兼容,但它在某些情况下可能有用。
在Solidity中进行压缩编码时,以下ABI限制不再强制执行:
动态类型(例如,字符串、数组等)完全按照它们的方式表示,没有任何偏移量或长度信息。
零填充不适用于短于32字节的静态类型(例如,uint8,bytes4等)。
更多规范请参见此处。
但是,值得注意的是,在未来的Solidity版本中,abi.encodePacked
正在考虑弃用。
理解ABI编码对于在Solidity中与智能合约进行交互至关重要。通过掌握函数签名,静态和动态类型编码以及abi
变量提供的各种编码方法的概念,你将有能力处理合约与外部世界之间的数据交换。
- 原文链接: extremelysunnyyk.medium....
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!