本文主要讨论了Solidity智能合约开发中ABI编码的重要性。
Solidity 很简单。
它是一种简单而优美的语言。
随着优秀的教育资源、课程、开发工具和 LLM 的兴起,学习和编写 Solidity 从未如此简单。
但这里有个残酷的真相 —— 如果每个人都很容易上手,那么脱颖而出就同样困难。
部署一个基本的 ERC20 合约就能赢得“智能合约工程师”称号的时代已经一去不复返了。
今天,精通意味着对 Solidity 的理解要超越表面。
GPT4 和 Claude 在编写基本到中级 Solidity、Foundry 测试用例,甚至理解像 Uniswap v2、Safe 等流行的代码库方面,正变得异常熟练。
那么,作为智能合约开发者,你该怎么做呢?
通过在 Solidity 和 EVM 中获得更深入的专业知识,做困难的事情。
编写基本的 solidity 智能合约 - 简单。
编写 gas 优化的、高度安全的智能合约,并对底层 EVM 工作原理有更深入的理解 - 这才是困难的。
我希望你的目标是做困难的事情。
并且记住:
做困难的事情不再是一种选择,
这是一种必需。
我在 Decipher Club 的主要目标之一是创建资源,以帮助 web3 构建者提升水平并脱颖而出。
我写了一篇关于 EVM 深度剖析的长篇文章系列,并创建了 Decipher EVM Puzzles,目的也是如此。
现在,我将开始一个关于 ABI 编码和解码的新系列—— 这是在 Solidity-EVM 中要掌握的最关键但也是最困难的主题之一。
本系列的目的是让你全面了解编码的实际工作方式。最重要的是,我希望你有一个基本的思维模型:
我在我的其中一个 推文 中解释了为什么掌握 ABI 编码和解码很重要。
对于 Solidity 开发者来说,abi 编码/解码是要掌握的关键技能
你在掌握它的时候,实际上学习了大量的关键概念:
- little and big endianness(大小端)
- calldata 的复杂性
- 数据偏移量
- 静态类型与动态类型的存储
- 函数选择器和参数编码
— Zaryab (@zaryab_eth) May 22, 2025
但是,这是一个扩展版本,旨在鼓励你深入研究它 并阅读本文章系列的后续部分。
让我们开始吧。
在学习 Solidity 时,大多数开发者都在表面上进行交互:编写函数,部署合约,通过像 Remix、Hardhat 或 Foundry 这样的工具来调用它们,并让库来处理剩下的事情。
然而,在表面之下,存在着一个强大而精确的通信协议 —— ABI,或 应用程序二进制接口 —— 它精确地定义了合约如何相互通信以及与外部世界通信。
如果你曾经调用过链上的一个函数,用 ethers.js
编写过一个脚本,或者在你的智能合约中使用过 abi.encode()
,那么你已经 使用 了 ABI 编码。
但是,
calldata
十六进制,然后想 这他妈的是什么鬼东西?让我解释一下为什么你应该学习它。
Solidity 可能是你编写的语言,
但 ABI 编码的语言是 EVM 说的语言。
每个函数调用都是 ABI 编码的
ABI 编码是将高级 Solidity 值 —— 比如数字、字符串、数组、结构体和函数参数 —— 转换为 以太坊虚拟机 (EVM) 可以理解、传输和执行的 标准化二进制格式 的过程。
在 Solidity 中,这种编码遵循 ABI 规范,它确保:
例如,当你调用:
myContract.foo(42, "hello");
你的钱包或脚本发送的是一个十六进制 blob(calldata)—— 类似于:
0xa9059cbb000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000068656c6c6f
这个 blob 包含:
如果合约错误地解释了哪怕是 一个字节,调用也会失败或行为异常。
但是,如果大部分的编码-解码都由库和 EVM 本身来处理,为什么你还要费心学习 ABI 编码是如何工作的呢?
这里有一些非常明显的答案。
深入理解 ABI 编码不仅可以解锁 calldata 的解码,还可以将你的 Solidity 开发提升到低级别的、系统感知的工程水平。
这里有一个区分中级 Solidity 开发者和高级开发者的简单方法:
你对默认 ABI 编码的理解有多深?
如果你可以描述如何编码一个结构体数组,而这些结构体本身又包含结构体数组,那么你就是高级开发者
(GPT-4?中级 Solidity 开发者)
— 0age (@z0age) March 15, 2023
学习 ABI 编码规范会让你学到比编码技术本身更多的关于 EVM 的知识。
例如,在理解编码机制的同时,你最终会学到一些关键的概念,比如:
所有这些概念对于你掌握以太坊虚拟机的复杂性 和美感 同样至关重要。
这里有一些问题:
a. 到底什么是 endianness(大小端)?solidity 使用哪种类型?
b. addresses 和 bytes 的填充是如何工作的?
c. 偏移量是如何工作的?静态类型和动态类型参数编码都有偏移量吗?
d. calldata 在 gas 优化中扮演什么角色?
e. 参数的类型(静态 vs 动态)为什么在编码中很重要?
如果你没有这些问题的答案,那么你对 solidity-evm 中 ABI 编码机制的了解就不够充分。
你将从本系列文章中受益最多。
当合约无声地失败或以不透明的消息回退时,能够读取原始 calldata 是猜测和知道之间的区别。
如果你知道如何轻松地读取原始 calldata,那么调试复杂的回退或逆向工程对你来说就不会是一场噩梦。
而这正是你与众不同的地方。
凭借对 ABI 编码工作原理的充分了解,你将能够:
在安全审计、漏洞分析或取证中,你通常只会收到交易的 calldata。
对 ABI 编码/解码的扎实理解可以让你将原始 calldata 解构为函数参数,识别被篡改的 payload 或解码恶意构造的偏移量。
例如,报告错误需要深入了解编码的工作原理:
Calldata 不是免费的 —— calldata 中的每个字节都要花费 gas。
自从 EIP-2028: 之后
回想一下我之前说过的话:成为一个更好的智能合约开发者意味着能够理解和编写高度 gas 优化的智能合约
深入了解 ABI 编码可以让你:
折叠未使用的或冗余的字节
优化动态类型布局(例如,压缩数组的头部/尾部)
在 abi.encode
与 abi.encodePacked
与 手动编码
之间进行选择
在内联汇编中编写内存高效的 calldata 构建器
abi.encode
vs encodePacked
vs encodeWithSelector
这三个方法不是可以互换的。
每个方法都有精确的规则,用于 填充,对齐,抗冲突性,尾部编码等等。
理解 ABI 规则可以让你清楚地知道何时使用:
abi.encode
→ 完全符合 ABI 的 32 字节对齐abi.encodePacked
→ 原始字节打包(例如,哈希)abi.encodeWithSelector
→ calldata 构造它可以帮助你避免在混合使用它们时产生的潜在错误,尤其是在自定义哈希或代理环境中。
对于像 Echidna、Foundry 或自定义工具这样的模糊测试器,你通常希望:
只有当你深入理解结构体、数组、动态值和嵌套类型的 ABI 布局时,这才有可能。
Solidity ABI 规范不仅仅是一个用于构建交易 calldata 的古怪约定。
它是 EVM 的基础通信协议,其影响范围涵盖函数、事件、错误、内存模型、工具和链下集成。
理解编码的工作原理不仅可以让你掌握函数参数和 calldata 编码,它还涵盖了更多内容。
以下是 Solidity 中依赖于底层 ABI 编码的扩展领域:
a. 事件
string
或 bytes
)使用 keccak256
进行哈希 —— 意味着如果你想 查询日志 或编写事件解析器,你必须理解 ABI 的事件编码规则。b. 自定义错误
InsufficientBalance(uint256 available, uint256 required)
这样的错误数据就像调用该函数一样进行编码,包含一个 4 字节的选择器和一些参数。returns (uint, string)
)被编码为一个 元组,与输入参数一样,遵循相同的 head-tail 逻辑。(head-tail 逻辑是我将在后续部分详细解释的内容).offset
和 .length
成员之所以有效,是因为它们的 ABI 定义的布局。合约中的每个接口定义(函数、事件、错误)都被序列化为一个 JSON ABI —— 它反映了 规范的 ABI 类型定义,包括元组和索引参数。
像 Hardhat、Foundry、Ethers.js、Wagmi 和 MetaMask 这样的工具都依赖于这个 ABI 模式。
就这样。
我试图提供许多理由来解释为什么:
在本系列的后续部分中,我的目标是让你掌握 ABI 编码工作原理的坚实的思维模型。我将尝试尽可能多地举例,以涵盖各种类型的编码机制。
我可能还会发布一个 Decipher ABI Games( 类似于 Decipher EVM puzzles )。敬请关注。
我们下一部分见。
- 原文链接: decipherclub.com/why-lea...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!