以太坊虚拟机操作码大全-阿里云开发者社区

开发者社区> 开发与运维> 正文

以太坊虚拟机操作码大全

简介: 以太坊EVM是栈式虚拟机,字长为256位,用于在以太坊区块链上运行智能合约。EVM采用单字节操作码(Opcode),因此全部操作码定义在00~ff区间。本文提供EVM操作码的速查简表和详表,方便以太坊智能合约开发人员、安全研究人员在开发、优化或分析以太坊智能合约的漏洞时作为指令手册使用。

以太坊EVM是栈式虚拟机,字长为256位,用于在以太坊区块链上运行智能合约。EVM采用单字节操作码(Opcode),因此全部操作码定义在00~ff区间。本文提供EVM操作码的速查简表和详表,方便以太坊智能合约开发人员、安全研究人员在开发、优化或分析以太坊智能合约的漏洞时作为指令手册使用。

用自己熟悉的语言学习 以太坊DApp开发Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、EVM操作码简表

00 01 02 03 04 05 06 07 08 09 0A 0B -- -- -- --
10 11 12 13 14 15 16 17 18岁 19 1A 1B 1C 一维 -- --
20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3楼
40 41 42 43 44 45 -- -- -- -- -- -- -- -- -- --
50 51 52 53 54 55 56 57 58 59 5A 5B -- -- -- --
60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6楼
70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7楼
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8楼
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9楼
A0 A1 A2 A3 A4 -- -- -- -- -- -- -- -- -- -- --
B0 B1 B2 -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
F0 F1 F2 F3 F4 F5 -- -- -- -- F A -- -- FD -- FF
## 2、EVM总览 以太坊虚拟机(EVM)是一个基于栈的big-endian虚拟机,字长为256位,用于在以太坊区块链上运行智能合约。 智能合约就像普通账户一样,不同之处在于它们在接收交易时运行EVM字节码,从而使其能够执行 计算和进一步交易。交易可以携带0或更多字节数据的有效负载,该有效负载用于指定与以太坊合约 的交互类型以及任何其他信息。 合约执行从字节码的开头开始。 除PUSH操作码采用立即数外,每个操作码均编码为一个字节。 所有操作码都从堆栈顶部弹出其操作数,然后推入其结果。 ## 3、合约创建 创建智能合约的交易的数据有效载荷本身就是字节码,它运行合约构造函数,设置初始合约状态并返回最终合约字节码。 一旦部署完成,构造函数就不会出现在部署后的合约中。 ## 4、合约交互 通常,合约提供公开的ABI,这是用户可以与以太坊智能合约进行交互的可支持方法的列表。为了与合约进行交互,用户需要提交一笔交易,该交易携带任何数量的wei(包括0)以及根据ABI格式化的数据有效负载,并指定交互的类型和任何其他参数。 合约运行时,有四种主要的数据处理方式: 调用数据/Call Data 这是与智能合约交易相关的数据。它通常包含一个4字节的方法标识符然后是序列化参数。 请参阅:CALLDATALOADCALLDATASIZECALLDATACOPY 栈 / Stack EVM维护一个uint256栈,用于保存局部变量、函数调用参数和返回地址。在返回地址和其他变量之间进行区分是比较困难的。 在此页面上,栈顶表示为stack [-1],后跟stack [-2],...:
stack[-1] stack[-2] ...
请参阅:PUSH1DUP1SWAP1POP 内存 / Memory 内存是uint8的数组,用于在执行合约时保存暂态数据。 它不会在不同交易之间持久化。 请参阅:MLOAD,MSTORE,MSTORE8 存储 / Storage 存储是一个持久的关联映射,以uint256为键、uint256为值。 所有的合约字段和映射都保存在存储器中。 可以使用web3.eth.getStorageAt(address,key)查看合约的存储字段。 请参阅:SLOADSSTORE ## 5、EVM操作码详表
uint8 助记符 栈输入 栈输出 表达式 备注说明
00 STOP - - STOP() 停止合约执行
01 ADD
a b
a + b
a + b (u)int256加法取模2256
02 MUL
a b
a b
a b (u)int256乘法取模2256
03 SUB
a b
a - b
a - b (u)int256减法取模2256
04 DIV
a b
a // b
a // b uint256除法
05 SDIV
a b
a // b
a // b int256除法
06 MOD
a b
a % b
a % b uint256取模
07 SMOD
a b
a % b
a % b int256取模
08 ADDMOD
a b N
(a + b) % N
(a + b) % N (u)int256加法取模N
09 MULMOD
a b N
(a b) % N
(a b) % N (u)int256乘法取模N
0A EXP
a b
a b
a b uint256指数结果取模2256
0B SIGNEXTEND
b x
y
y = SIGNEXTEND(x, b) 将x从 (b + 1) 8 位有符号扩展为 256位
0C Invalid - - - -
0D Invalid - - - -
0E Invalid - - - -
0F Invalid - - - -
10 LT
a b
a < b
a < b uint256比较
11 GT
a b
a > b
a > b uint256比较
12 SLT
a b
a < b
a < b int256比较
13 SGT
a b
a > b
a > b int256比较
14 EQ
a b
a == b
a == b (u)int256相等比较
15 ISZERO
a
a == 0
a == 0 (u)int256零比较
16 AND
a b
a & b
a & b 256位的位与计算
17 OR
a b
a | b
a | b 256位的位或计算
18 XOR
a b
a ^ b
a ^ b 256位的异或计算
19 NOT
a
~a
~a 256位的位取反计算
1A BYTE
i x
y
y = (x >> (248 - i 8)) & 0xFF 返回(u)int256 x从最高字节开始的第i字节
1B SHL
shift value
value << shift
value << shift 256位左移
1C SHR
shift value
value >> shift
value >> shift 256位右移
1D SAR
shift value
value >> shift
value >> shift int256右移位
1E Invalid - - - -
1F Invalid - - - -
20 SHA3
offset length
hash
hash = keccak256(memory[offset:offset+length]) keccak256哈希
21 Invalid - - - -
22 Invalid - - - -
23 Invalid - - - -
24 Invalid - - - -
25 Invalid - - - -
26 Invalid - - - -
27 Invalid - - - -
28 Invalid - - - -
29 Invalid - - - -
2A Invalid - - - -
2B Invalid - - - -
2C Invalid - - - -
2D Invalid - - - -
2E Invalid - - - -
2F Invalid - - - -
30 ADDRESS -
address(this)
address(this) 当前执行合约的地址
31 BALANCE
addr
address(addr).balance
address(addr).balance 指定地址的余额,单位wei
32 ORIGIN -
tx.origin
tx.origin 交易发起方地址
33 CALLER -
msg.caller
msg.caller 消息调用方地址
34 CALLVALUE -
msg.value
msg.value 以wei为单位的消息携带金额
35 CALLDATALOAD
i
msg.data[i:i+32]
msg.data[i:i+32] 从消息数据读取一个(u)int256
36 CALLDATASIZE -
msg.data.size
msg.data.size 以字节为单位的消息数据长度
37 CALLDATACOPY
destOffset offset length
- memory[destOffset:destOffset+length] = msg.data[offset:offset+length] 拷贝消息数据
38 CODESIZE -
address(this).code.size
address(this).code.size 以字节为单位的当前执行合约的长度
39 CODECOPY
destOffset offset length
- memory[destOffset:destOffset+length] = address(this).code[offset:offset+length] 拷贝当前执行合约的字节码
3A GASPRICE -
tx.gasprice
tx.gasprice 当前执行交易的单位gas价格,以wei为单位
3B EXTCODESIZE
addr
address(addr).code.size
address(addr).code.size 指定地址处的合约字节码长度,以字节为单位
3C EXTCODECOPY
addr destOffset offset length
- memory[destOffset:destOffset+length] = address(addr).code[offset:offset+length] 拷贝合约字节码
3D RETURNDATASIZE -
size
size = RETURNDATASIZE() 最后一个外部调用的返回数据的长度,以字节为单位
3E RETURNDATACOPY
destOffset offset length
- memory[destOffset:destOffset+length] = RETURNDATA[offset:offset+length] 拷贝返回的数据
3F EXTCODEHASH
addr
hash
hash = address(addr).exists ? keccak256(address(addr).code) : 0 指定地址的合约字节码的哈希,请参考EIP-1052事件
40 BLOCKHASH
blockNumber
hash
hash = block.blockHash(blockNumber) 指定区块的哈希,仅适用于最近的256个区块,不包括当前区块
41 COINBASE -
block.coinbase
block.coinbase 当前区块矿工的地址
42 TIMESTAMP -
block.timestamp
block.timestamp 当前区块的UNIX时间戳,以秒为单位
43 NUMBER -
block.number
block.number 当前区块号
44 DIFFICULTY -
block.difficulty
block.difficulty 当前区块难度
45 GASLIMIT -
block.gaslimit
block.gaslimit 当前区块GAS上限
46 Invalid - - - -
47 Invalid - - - -
48 Invalid - - - -
49 Invalid - - - -
4A Invalid - - - -
4B Invalid - - - -
4C Invalid - - - -
4D Invalid - - - -
4E Invalid - - - -
4F Invalid - - - -
50 POP
_
- POP() 弹出栈顶(u)int256 并丢弃
51 MLOAD
offset
value
value = memory[offset:offset+32] 从内存读取一个(u)int256
52 MSTORE
offset value
- memory[offset:offset+32] = value 向内存写入一个(u)int256
53 MSTORE8
offset value
- memory[offset] = value & 0xFF 向内存写入一个uint8
54 SLOAD
key
value
value = storage[key] 从存储读取一个(u)int256
55 SSTORE
key value
- storage[key] = value 向存储写入一个(u)int256
56 JUMP
destination
- $pc = destination 无条件跳转
57 JUMPI
destination condition
- $pc = cond ? destination : $pc + 1 条件为真时跳转
58 PC -
$pc
$pc 程序计数器
59 MSIZE -
size
size = MSIZE() 当前合约执行的内存大小,以字节为单位
5A GAS -
gasRemaining
gasRemaining = GAS() 剩余的GAS
5B JUMPDEST - - 用于注解可能的跳转目标的元数据
5C Invalid - - - -
5D Invalid - - - -
5E Invalid - - - -
5F Invalid - - - -
60 PUSH1 -
uint8
PUSH(uint8) 将1字节数值压入栈
61 PUSH2 -
uint16
PUSH(uint16) 将2字节数值压入栈
62 PUSH3 -
uint24
PUSH(uint24) 将3字节数值压入栈
63 PUSH4 -
uint32
PUSH(uint32) 将4字节数值压入栈
64 PUSH5 -
uint40
PUSH(uint40) 将5字节数值压入栈
65 PUSH6 -
uint48
PUSH(uint48) 将6字节数值压入栈
66 PUSH7 -
uint56
PUSH(uint56) 将7字节数值压入栈
67 PUSH8 -
uint64
PUSH(uint64) 将8字节数值压入栈
68 PUSH9 -
uint72
PUSH(uint72) 将9字节数值压入栈
69 PUSH10 -
uint80
PUSH(uint80) 将10字节数值压入栈
6A PUSH11 -
uint88
PUSH(uint88) 将11字节数值压入栈
6B PUSH12 -
uint96
PUSH(uint96) 将12字节数值压入栈
6C PUSH13 -
uint104
PUSH(uint104) 将13字节数值压入栈
6D PUSH14 -
uint112
PUSH(uint112) 将14字节数值压入栈
6E PUSH15 -
uint120
PUSH(uint120) 将15字节数值压入栈
6F PUSH16 -
uint128
PUSH(uint128) 将16字节数值压入栈
70 PUSH17 -
uint136
PUSH(uint136) 将17字节数值压入栈
71 PUSH18 -
uint144
PUSH(uint144) 将18字节数值压入栈
72 PUSH19 -
uint152
PUSH(uint152) 将19字节数值压入栈
73 PUSH20 -
uint160
PUSH(uint160) 将20字节数值压入栈
74 PUSH21 -
uint168
PUSH(uint168) 将21字节数值压入栈
75 PUSH22 -
uint176
PUSH(uint176) 将22字节数值压入栈
76 PUSH23 -
uint184
PUSH(uint184) 将23字节数值压入栈
77 PUSH24 -
uint192
PUSH(uint192) 将24字节数值压入栈
78 PUSH25 -
uint200
PUSH(uint200) 将25字节数值压入栈
79 PUSH26 -
uint208
PUSH(uint208) 将26字节数值压入栈
7A PUSH27 -
uint216
PUSH(uint216) 将27字节数值压入栈
7B PUSH28 -
uint224
PUSH(uint224) 将28字节数值压入栈
7C PUSH29 -
uint232
PUSH(uint232) 将29字节数值压入栈
7D PUSH30 -
uint240
PUSH(uint240) 将30字节数值压入栈
7E PUSH31 -
uint248
PUSH(uint248) 将31字节数值压入栈
7F PUSH32 -
uint256
PUSH(uint256) 将32字节数值压入栈
80 DUP1
value
value value
PUSH(value) 克隆栈上最后一个值
81 DUP2
_ value
value _ value
PUSH(value) 克隆栈上倒数第二个值
82 DUP3
_ _ value
value _ _ value
PUSH(value) 克隆栈上倒数第三个值
83 DUP4
_ _ _ value
value _ _ _ value
PUSH(value) 克隆栈上倒数第四个值
84 DUP5
... value
value ... value
PUSH(value) 克隆栈上倒数第五个值
85 DUP6
... value
value ... value
PUSH(value) 克隆栈上倒数第六个值
86 DUP7
... value
value ... value
PUSH(value) 克隆栈上倒数第七个值
87 DUP8
... value
value ... value
PUSH(value) 克隆栈上倒数第八个值
88 DUP9
... value
value ... value
PUSH(value) 克隆栈上倒数第九个值
89 DUP10
... value
value ... value
PUSH(value) 克隆栈上倒数第10个值
8A DUP11
... value
value ... value
PUSH(value) 克隆栈上倒数第11个值
8B DUP12
... value
value ... value
PUSH(value) 克隆栈上倒数第12个值
8C DUP13
... value
value ... value
PUSH(value) 克隆栈上倒数第13个值
8D DUP14
... value
value ... value
PUSH(value) 克隆栈上倒数第14个值
8E DUP15
... value
value ... value
PUSH(value) 克隆栈上倒数第15个值
8F DUP16
... value
value ... value
PUSH(value) 克隆栈上倒数第16个值
90 SWAP1
a b
b a
a, b = b, a 交换栈顶两个成员
91 SWAP2
a _ b
b _ a
a, b = b, a 交换栈顶与倒数第3个成员
92 SWAP3
a _ _ b
b _ _ a
a, b = b, a 交换栈顶与倒数第4个成员
93 SWAP4
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第5个成员
94 SWAP5
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第6个成员
95 SWAP6
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第7个成员
96 SWAP7
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第8个成员
97 SWAP8
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第9个成员
98 SWAP9
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第10个成员
99 SWAP10
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第11个成员
9A SWAP11
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第12个成员
9B SWAP12
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第13个成员
9C SWAP13
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第14个成员
9D SWAP14
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第15个成员
9E SWAP15
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第16个成员
9F SWAP16
a ... b
b ... a
a, b = b, a 交换栈顶与倒数第17个成员
A0 LOG0
offset length
- LOG0(memory[offset:offset+length]) 触发事件
A1 LOG1
offset length topic0
- LOG1(memory[offset:offset+length], topic0) 触发事件
A2 LOG2
offset length topic0 topic1
- LOG2(memory[offset:offset+length], topic0, topic1) 触发事件
A3 LOG3
offset length topic0 topic1 topic2
- LOG3(memory[offset:offset+length], topic0, topic1, topic2) 触发事件
A4 LOG4
offset length topic0 topic1 topic2 topic3
- LOG4(memory[offset:offset+length], topic0, topic1, topic2, topic3) 触发事件
A5 Invalid - - - -
A6 Invalid - - - -
A7 Invalid - - - -
A8 Invalid - - - -
A9 Invalid - - - -
AA Invalid - - - -
AB Invalid - - - -
AC Invalid - - - -
AD Invalid - - - -
AE Invalid - - - -
AF Invalid - - - -
B0 PUSH - - ??? ???
B1 DUP - - ??? ???
B2 SWAP - - ??? ???
B3 Invalid - - - -
B4 Invalid - - - -
B5 Invalid - - - -
B6 Invalid - - - -
B7 Invalid - - - -
B8 Invalid - - - -
B9 Invalid - - - -
BA Invalid - - - -
BB Invalid - - - -
BC Invalid - - - -
BD Invalid - - - -
BE Invalid - - - -
BF Invalid - - - -
C0 Invalid - - - -
C1 Invalid - - - -
C2 Invalid - - - -
C3 Invalid - - - -
C4 Invalid - - - -
C5 Invalid - - - -
C6 Invalid - - - -
C7 Invalid - - - -
C8 Invalid - - - -
C9 Invalid - - - -
CA Invalid - - - -
CB Invalid - - - -
CC Invalid - - - -
CD Invalid - - - -
CE Invalid - - - -
CF Invalid - - - -
D0 Invalid - - - -
D1 Invalid - - - -
D2 Invalid - - - -
D3 Invalid - - - -
D4 Invalid - - - -
D5 Invalid - - - -
D6 Invalid - - - -
D7 Invalid - - - -
D8 Invalid - - - -
D9 Invalid - - - -
DA Invalid - - - -
DB Invalid - - - -
DC Invalid - - - -
DD Invalid - - - -
DE Invalid - - - -
DF Invalid - - - -
E0 Invalid - - - -
E1 Invalid - - - -
E2 Invalid - - - -
E3 Invalid - - - -
E4 Invalid - - - -
E5 Invalid - - - -
E6 Invalid - - - -
E7 Invalid - - - -
E8 Invalid - - - -
E9 Invalid - - - -
EA Invalid - - - -
EB Invalid - - - -
EC Invalid - - - -
ED Invalid - - - -
EE Invalid - - - -
EF Invalid - - - -
F0 CREATE
value offset length
addr
addr = new memory[offset:offset+length].value(value) 创建子合约
F1 CALL
gas addr value argsOffset argsLength retOffset retLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).call.gas(gas).value(value) (memory[argsOffset:argsOffset+argsLength]) 调用另一个合约中的方法
F2 CALLCODE
gas addr value argsOffset argsLength retOffset retLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).callcode.gas(gas).value(value) (memory[argsOffset:argsOffset+argsLength]) ???
F3 RETURN
offset length
- return memory[offset:offset+length] 从这个合约调用返回
F4 DELEGATECALL
gas addr argsOffset argsLength retOffset retLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).delegatecall.gas(gas) (memory[argsOffset:argsOffset+argsLength]) 使用当前合约的存储调用另一个合约的方法
F5 CREATE2
value offset length salt
addr
addr = new memory[offset:offset+length].value(value) 使用确定的地址创建子合约,参见see EIP-1014
F6 Invalid - - - -
F7 Invalid - - - -
F8 Invalid - - - -
F9 Invalid - - - -
FA STATICCALL
gas addr argsOffset argsLength retOffset retLength
success
success, memory[retOffset:retOffset+retLength] = address(addr).staticcall.gas(gas) (memory[argsOffset:argsOffset+argsLength]) 调用另一个合约的方法,不允许合约创建、事件发送、存储修改和合约销毁等引起状态改变的方法,参见EIP-214
FB Invalid - - - -
FC Invalid - - - -
FD REVERT
offset length
- revert(memory[offset:offset+length]) 回滚交易并返回数据
FE Invalid - - - -
FF SELFDESTRUCT
addr
- selfdestruct(address(addr)) 销毁合约并将所有资金发送给addr地址

原文链接:EVM操作码速查 — 汇智网

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章