本文是Huff语言系列教程的第一部分,介绍了Huff语言的特性、语法和结构,以及如何使用Huff构建优化的智能合约。通过ERC20的transfer函数和SumArray谜题两个实际案例,展示了Huff在gas优化方面的优势,并与Solidity进行了对比。文章还介绍了Huff的开发流程和工具。
在竞争激烈的以太坊开发领域,每一 gas 单位都至关重要,Huff 是一种将智能合约优化推向极限的工具,因此脱颖而出。Huff 最初由 Aztec Protocol 团队开发,用于优化他们的 Weierstrudel 椭圆曲线库。Huff 是一种基于宏的低级语言,专为编写高效的 EVM 字节码而设计。它提供对 EVM 操作码的直接访问,使开发人员能够无与伦比地控制执行和性能。
然而,这种强大功能伴随着陡峭的学习曲线、极少的抽象和几乎没有内置的安全性。Huff 并不适合胆小的人 —— 它适用于那些愿意深入研究 EVM 内部结构以获得最大效率的开发人员。
这个分为三个部分的文章系列探讨了 Huff 的语法、优点和实际应用。在第 1 部分中,我们讨论:
transfer
和 SumArray 谜题之类的用例Huff 是一种 EVM 的特定领域语言,完全专注于 gas 效率。 它去除了高级的便利,暴露了以太坊执行环境的本质。
尽管 Huff 存在难度,但它在对性能至关重要的场景中表现出色:
Huff 的核心围绕以下内容构建:
常量使用 #define constant
将原始值注入到字节码中:
##define constant BALANCE_SLOT = 0x00
宏是构建逻辑的主要方式。它们显式定义输入/输出堆栈大小并使用原始操作码。
示例:安全加法
##define macro MATH__ADD() = takes(2) returns(1) {
// 堆栈:a, b
dup2 add
dup1 swap2 gt
[OVERFLOW_ERROR] jumpi
}
Huff 不使用 Solidity 风格的选择器。相反,你可以使用 calldataload
和 jumpi
手动路由函数:
##define macro MAIN() = takes(0) returns(0) {
0x00 calldataload
0xe0 shr
dup1 0xa9059cbb eq transfer jumpi
0x00 0x00 revert
}
让我们在纯 Huff 中构建一个简单的 transfer(address,uint256)
。
##define constant BALANCE_SLOT = 0x00
##define constant TRANSFER_SIGNATURE = 0xa9059cbb
##define constant TRANSFER_EVENT = 0xDDF252AD...
##define macro ADDRESS_MASK() = takes(1) returns(1) {
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff and
}
##define macro TRANSFER_INIT() = takes(0) returns(6) {
0x04 calldataload ADDRESS_MASK() // recipient
caller // sender
[TRANSFER_EVENT] // event signature
0x20 0x00 // memory layout
0x24 calldataload // amount
}
##define macro TRANSFER_GIVE_TO() = takes(6) returns(7) {
dup6 0x00 mstore
0x40 0x00 sha3
dup1 sload
dup3 add
dup1 dup4 gt
swap2 sstore
}
##define macro TRANSFER_TAKE_FROM() = takes(7) returns(8) {
caller 0x00 mstore
0x40 0x00 sha3
dup1 sload
dup4 dup2 sub
dup5 swap3 sstore
lt
}
##define macro TRANSFER() = takes(0) returns(0) {
TRANSFER_INIT()
TRANSFER_GIVE_TO()
TRANSFER_TAKE_FROM()
callvalue or or throw_error jumpi
0x00 mstore log3
0x01 0x00 mstore
0x20 0x00 return
}
##define macro MAIN() = takes(0) returns(0) {
0x00 calldataload 0xe0 shr
dup1 [TRANSFER_SIGNATURE] eq transfer jumpi
0x00 0x00 revert
transfer:
TRANSFER()
throw_error:
0x00 0x00 revert
}
Transfer
事件SumArray 谜题从 calldata 中获取 uint256[]
并返回它们的总和。
##define macro SUM_ARRAY() = takes(0) returns(0) {
0x44 calldatasize sub
push0
push0
loopBegin:
dup3 dup2 0x20 mul lt iszero end jumpi
dup1 0x20 mul 0x44 add calldataload
dup3 add
swap2 pop
0x01 add
loopBegin jump
end:
pop
push0 mstore
0x20 push0 return
}
##define macro MAIN() = takes(0) returns(0) {
0x00 calldataload 0xe0 shr
dup1 0x1e2aea06 eq sumArray jumpi
0x00 0x00 revert
sumArray:
SUM_ARRAY()
}
.huff
文件huffc contracts/MyContract.huff --bytecode
使用 Foundry 进行测试
使用 forge script
部署
在第 1 部分中,我们探讨了是什么让 Huff 成为一种独特而强大的语言,适用于专注于 Gas 优化的 EVM 开发人员。我们介绍了语法、宏系统和两个工作示例:ERC20.transfer()
和 SumArray
。
👉 在第 2 部分中,我们将比较 Huff 与 Solidity 和 Yul,并继续构建 ERC20 代币。
👉 在第 3 部分中,我们将探索高级优化和真实的 DeFi 用例。
- 原文链接: medium.com/@ankitacode11...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!