以太坊智能合约ABI详解

在以太坊生态系统中, ABI 是从区块链外部与合约进行交互以及合约与合约间进行交互的一种标准方式。本文让我们了解一下智能合约的 ABI 是什么。

ABI是什么

在计算机科学中,ABI(应用程序二进制接口 Application Binary Interface)是两个程序模块之间的接口,通常是操作系统和用户程序之间的接口。

EVM(以太坊虚拟机)是以太坊网络的核心组件,智能合约是存储在以太坊区块链上的代码片段,它在 EVM 上执行。用 Solidity 或 Vyper 等高级语言编写的智能合约需要用 EVM 可执行字节码编译。当部署智能合约时,这个字节码存储在区块链上,并与一个地址相关联。对于以太坊和 EVM 来说,智能合约就是这个字节码序列。为了访问在高级语言中定义的函数,用户需要将名称和参数转换为字节表示,以便字节代码使用它。为了解释在响应中发送的字节,用户需要转换回在高级语言中定义的返回值元组。为 EVM 编译的语言对这些转换保持严格的约定,但是为了执行这些转换,必须知道与操作相关的精确名称和类型。ABI 精确地记录了这些名称和类型,格式易于解析且可以在方法调用和智能合约操作之间进行转换。

它非常类似于 API(用程序接口),一种人类可读的代码接口表示。ABI 定义了用于与二进制合约交互的方法和结构,就像 API 所做的那样,只是在较低的级别上。ABI 指示函数的调用者将所需的信息(如函数签名和变量声明)编码为 EVM 能够理解的格式,以便在字节码中调用该函数,这被称为 ABI 编码。ABI 编码大部分是自动化的,由 REMIX 或钱包等与区块链交互的编译器负责。合约 ABI 用 JSON 格式表示。对于如何编码和解码合约 ABI 有明确的规范。

理解ABI的元素

合约 ABI 的 JSON 格式由各种函数或事件描述组成。

下面是一个函数的 ABI 描述中的元素:

  • type:定义函数类型。可以是 function constructorreceive(对于 receive ether 函数),或者 fallback(对于 default 函数)

  • name:定义函数的名称

  • input:它是一个对象数组,用于定义参数,每个对象有:

    • name:定义参数的名称
    • type:定义参数的规范类型。例如 uint256
  • components:用于定义元组类型,元组类型表示为 type = tuple[元组元素的其他属性,如 name, type 放在这里]

  • output:输出对象的数组,类似于输入

  • stateMutability:定义函数的可变性。它可以是以下值之一:

    • pure:指定不读取或写入区块链状态
    • view:指定当区块链状态是可读的,但不能进行修改
    • nonpayable:这是默认的可变性,在代码中编写函数时不需要提及,这意味着函数不接受 Ether
    • payable:这个值意味着一个函数接受 Ether 并可以读写区块链状态

注:构造函数和回退函数的 ABI 中名称和输出字段为空;对于回退函数,甚至输入字段也是空的。

以下是事件ABI描述中的元素:

  • type:它总是 event

  • name:定义事件的名称

  • input:它是一个对象数组,用于定义参数,每个对象有:

    • name:定义参数的名称
    • type:定义参数的规范类型。例如 uint256
  • components:用于定义元组类型,元组类型表示为 type = tuple[元组元素的其他属性,如 name, type 放在这里]

  • 索引:如果该字段是日志主题的一部分,则为 true,如果它是日志的数据段之一,则为 false

  • anonymous:如果事件在合约代码中被声明为匿名,该字段为 true

如何获取/生成ABI

最常见的方法之一是在智能合约编译完成后,使用 REMIX IDE 的 compile 选项卡下的 ABI 按钮复制 ABI。
以太坊智能合约ABI详解_第1张图片

另外还有以下几种生成 ABI 的方法:

  • 使用 solc 编译和生成 ABI;
  • 使用 truffle 框架编译和生成 ABI。

要安装 solc 和 truffle,我们需要已安装 node.js 和 npm。

下面是一个合约的例子 HelloWorld.sol,这个合约定义了一个状态变量和两个函数,其中一个函数 set 用来更新状态变量的值,函数 get 用来获取状态变量的值。我们来为这个合约编译并生成 ABI。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

// 第一个合约
contract HelloWorld {
    // 状态变量
    string public str = "Hello World!";

    // set 函数
    function set(string memory s) public {
        str = s;
    }

    // get 函数
    function get() public view returns(string memory) {
        return str;
    }
}

上面这个合约编译后,在合约相同的目录中将创建一个名为 HelloWorld.json 的文件,它是一个 JSON 格式的文件,其 ABI 如下所示:

[
	{
		"inputs": [],
		"name": "get",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "string",
				"name": "s",
				"type": "string"
			}
		],
		"name": "set",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "str",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	}
]

你可能感兴趣的:(以太坊,智能合约,区块链)