当前位置: 首页 > news >正文

Solidity学习 - ABI 应用二进制接口

文章目录

    • 一、ABI 基础概念
      • 1. ABI 与 API 的区别
      • 2. ABI 的核心作用
    • 二、ABI 接口描述
      • 1. 编译后的产物
      • 2. ABI JSON 格式示例
      • 3. ABI JSON 关键字段说明
    • 三、ABI 编码
      • 1. 编码示例
      • 2. 编码数据的组成
      • 3. Solidity 中的编码函数
    • 四、ABI 解码
      • 1. 解码的基本概念
      • 2. 事件日志的解码
    • 五、ABI 编解码可视化工具

一、ABI 基础概念

1. ABI 与 API 的区别

  • API(应用程序接口):是两个软件之间进行通信的桥梁,用于访问某个服务。
  • ABI(应用二进制接口):定义了智能合约中可交互的方法、事件和错误,是与 EVM(以太坊虚拟机)交互的桥梁。

2. ABI 的核心作用

EVM 只能识别和运行由 0 和 1 组成的二进制数据,因此在调用函数时,需要借助 ABI 将人类可读的函数转化为 EVM 可读的字节码。从本质上说,ABI 是编码和解码规范,用于规范外部与 EVM 的交互,也可用于合约间的交互。

二、ABI 接口描述

1. 编译后的产物

在 Solidity 中编译代码后,会得到两个重要的 artifact(产物):

  • bytecode(字节码):合约部署到区块链上的实际代码。
  • ABI 接口描述:是 JSON 格式的文件,定义了智能合约中外部可交互的方法、事件和可解释的错误。

2. ABI JSON 格式示例

以 Counter 合约为例,其编译后生成的 ABI 是一个 JSON 格式的数组,每个对象定义了合约中可公开调用的方法(函数)、声明的事件及错误等。以下是 Counter 合约及其对应的 ABI 示例:

contract Counter {uint public counter;address private owner;   error NotOwner();   event Set(uint _value);  constructor() {owner = msg.sender;}   function set(uint x) public {       if(owner != msg.sender)  revert NotOwner();       counter = x;emit Set(x);   }
}

对应的 ABI 如下:

[{"inputs": [],         "name": "NotOwner",         "type": "error"},{"anonymous": false,         "inputs": [{                 "indexed": false,                 "internalType": "uint256",                 "name": "_value",                 "type": "uint256"}],"name": "Set",         "type": "event"},{"inputs": [],         "name": "counter",         "outputs": [{                 "internalType": "uint256",                 "name": "",                 "type": "uint256"}],         "stateMutability": "view",         "type": "function"},{"inputs": [{                 "internalType": "uint256",                 "name": "x",                 "type": "uint256"}],"name": "set",         "outputs": [],         "stateMutability": "nonpayable",         "type": "function"}
]

3. ABI JSON 关键字段说明

  • type:定义是函数、事件或错误等。
  • name:表示函数名称、事件名称、自定义错误名称。
  • inputs:函数输入参数。
  • outputs:函数输出参数。

三、ABI 编码

1. 编码示例

以调用部署在 sepolia 网络上的 Counter 合约的 set() 函数,并传入参数 10 为例,经过 ABI 编码后提交到链上的数据是 0x60fe47b1000000000000000000000000000000000000000000000000000000000000000a

2. 编码数据的组成

该编码数据包含两个部分:

  • 函数选择器(前 4 个字节)0x60fe47b1,它是 ABI 描述中函数的签名 set(uint256) 进行 keccak256 哈希运算后取前 4 个字节,即 bytes4(keccak256("set(uint256)")) == 0x60fe47b1
  • 参数编码:参数 10 的十六进制是 a,然后扩展到 32 个字节。

3. Solidity 中的编码函数

Solidity 中有 5 个用于编码的函数:

  • abi.encode:按 EVM 标准规则对参数编码,每个参数按 32 个字节填充 0 后再拼在一起,用于与合约交互时编码参数。
  • abi.encodePacked:紧密编码,参数编码拼接时不填充 0,使用实际占用空间拼接,若结果不是 32 字节整数倍数,在末尾填充 0,例如在使用 EIP712 时需要用到。
  • abi.encodeWithSignature:对函数签名及参数进行编码,第一个参数是函数签名,后面按 EVM 标准规则对参数编码,可直接获得调用函数所需的 ABI 编码数据。
  • abi.encodeWithSelector:与 abi.encodeWithSignature 功能类似,第一个参数为 4 个字节的函数选择器。
  • abi.encodeCall:通过函数指针对函数及参数编码,执行编码时进行完整的类型检查,确保类型匹配函数签名。

四、ABI 解码

1. 解码的基本概念

解码是编码的“逆过程”。区块链浏览器能将提交给链上的 0x60fe47b10000000...0a 显示为函数 set(uint256 x),就是对数据进行了解码。需要注意的是,仅能对参数进行解码,函数选择器因使用了 keccak256 哈希运算(哈希不可逆)无法直接解码,但开源合约代码后,区块链浏览器可计算出所有函数的函数选择器,从而通过函数选择器匹配对应的函数签名。

2. 事件日志的解码

ABI 解码的一个重要场景是解析交易中的事件日志。日志包含 Topics 和 Data 两部分,其中 Topics 的第一个主题是事件签名的 Keccak256 哈希。通过匹配该哈希值,可知道 EVM 产生的日志由哪个事件生成,进而根据事件的参数列表解析日志数据。Solidity、web3.js、ethers.js 库都提供了解码函数。

五、ABI 编解码可视化工具

ChainToolDAO 开发了几个可视化工具,可帮助进行编解码:

  • 函数选择器的查询及反查:https://chaintool.tech/querySelector
  • 事件签名的 Topic 查询:https://chaintool.tech/topicID
  • Hash 工具(提供 Keccak-256 及 Base64):https://chaintool.tech/hashTool
  • 交易数据(calldata)的编码与解码:https://chaintool.tech/calldata
http://www.lqws.cn/news/552421.html

相关文章:

  • 叉车考试真题(含答案)pdf下载
  • 权限提升-工作流
  • React用户交互事件
  • 一款支持多日志器、多级别、多落地方式的同异步日志系统
  • ViewModel 使用总结:普通、Shared 及嵌套 Fragment 场景
  • 栅极驱动器选的好SiC MOSFET高效又安全
  • RabbitMQ-基础篇
  • StarRocks 向量索引如何让大模型“记性更好”?
  • 【Linux】理解进程状态与优先级:操作系统中的调度原理
  • linux安装vscode
  • ABP VNext + 多数据库混合:SQL Server+PostgreSQL+MySQL
  • .NET C# async/定时任务的异步线程池调度方案最大线程数‌ = 处理器核心数 × 250
  • python 文件处理工具(包含文件读写、后缀获取、压缩和解压、文件夹遍历等)
  • C++ STL深度剖析:Stack、queue、deque容器适配器核心接口
  • [Linux]从零开始的STM32MP157移植Ubuntu根文件系统教程
  • 华为云Flexus+DeepSeek征文|基于Dify构建文本/图像/视频生成工作流
  • linux面试常考
  • 【linux】Vm虚拟机ubuntu的接口ip掉了
  • scrapy+django+pyecharts+mysql 实现西安游客行为分析系统大屏_用户画像_空间分析_路线智能推荐
  • Minio入门+适配器模式(实战教程)
  • 鸿蒙5:布局组件
  • libxlsxwriter: 一个轻量级的跨平台的C++操作Excel的开源库
  • HTML表格中<tfoot>标签用法详解
  • 设计模式(策略,工厂,单例,享元,门面)+模板方法
  • 【数据挖掘】贝叶斯分类学习—NaiveBayes
  • git 挑选:git cherry-pick
  • GO 语言学习 之 函数
  • 为何需要防爆平板?它究竟有何能耐?
  • UniApp Vue3 模式下实现页面跳转的全面指南
  • 【笔记】 Docker目录迁移脚本