我最近在重新学以太坊opcodes,也写一个“WTF EVM Opcodes极简入门”,供小白们使用。
所有代码和教程开源在github: github.com/WTFAcademy/WTF-Opcodes
这一讲,我们将介绍EVM中与返回数据(return)相关的3个指令: RETURN
,RETURNDATASIZE
,和RETURNDATACOPY
。它们是Solidity中return
关键字的基础。
返回数据
EVM的返回数据,通常称为returnData
,本质上是一个字节数组。它不遵循固定的数据结构,而是简单地表示为连续的字节。当合约函数需要返回复杂数据类型(如结构体或数组)时,这些数据将按照ABI规范被编码为字节,并存储在returnData
中,供其他函数或合约访问。
为了支持这一特性,我们需要为我们的简化版EVM添加一个新属性以保存返回数据:
返回相关指令
1. RETURN
- 操作码:
0xF3
- gas消耗:内存扩展成本。
- 功能:从指定的内存位置提取数据,存储到
returnData
中,并终止当前的操作。此指令需要从堆栈中取出两个参数:内存的起始位置mem_offset
和数据的长度length
。 - 使用场景:当需要将数据返回给外部函数或交易时。
2. RETURNDATASIZE
- 操作码:
0x3D
- gas消耗:2
- 功能:将
returnData
的大小推入堆栈。 - 使用场景:使用上一个调用返回的数据。
3. RETURNDATACOPY
- 操作码:
0x3E
- gas消耗: 3 + 3 * 数据长度 + 内存扩展成本
- 功能:将
returnData
中的某段数据复制到内存中。此指令需要从堆栈中取出三个参数:内存的起始位置mem_offset
,返回数据的起始位置return_offset
,和数据的长度length
。 - 使用场景:使用上一个调用返回的部分数据。
测试
-
RETURN: 我们运行一个包含
RETURN
指令的字节码:60a26000526001601ff3
(PUSH1 a2 PUSH1 0 MSTORE PUSH1 1 PUSH1 1f RETURN)。这个字节码将a2
存在内存中,然后使用RETURN
指令将a2
复制到returnData
中。 -
RETURNDATASIZE:我们将
returnData
设为aaaa
,然后用RETURNDATASIZE
将它的长度压入堆栈。 -
RETURNDATACOPY:我们将
returnData
设为aaaa
,然后运行一个包含RETURNDATACOPY
指令的字节码:60025F5F3E
(PUSH1 2 PUSH0 PUSH0 RETURNDATACOPY),将返回数据存入内存。
总结
这一讲,我们学习了EVM中与返回数据相关的3个指令:RETURN
、RETURNDATASIZE
,和RETURNDATACOPY
,并通过代码示例为极简EVM添加了对这些指令的支持。目前,我们已经学习了144个操作码中的134个(93%)!