Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libevmasm/Instruction.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/** @file Instruction.h
19
 * @author Gav Wood <i@gavwood.com>
20
 * @date 2014
21
 */
22
23
#pragma once
24
25
#include <libevmasm/Exceptions.h>
26
#include <libsolutil/Common.h>
27
#include <libsolutil/Assertions.h>
28
#include <liblangutil/EVMVersion.h>
29
#include <liblangutil/Exceptions.h>
30
31
namespace solidity::evmasm
32
{
33
34
/// Virtual machine bytecode instruction.
35
enum class Instruction: uint8_t
36
{
37
  STOP = 0x00,              ///< halts execution
38
  ADD,                      ///< addition operation
39
  MUL,                      ///< multiplication operation
40
  SUB,                      ///< subtraction operation
41
  DIV,                      ///< integer division operation
42
  SDIV,                     ///< signed integer division operation
43
  MOD,                      ///< modulo remainder operation
44
  SMOD,                     ///< signed modulo remainder operation
45
  ADDMOD,                   ///< unsigned modular addition
46
  MULMOD,                   ///< unsigned modular multiplication
47
  EXP,                      ///< exponential operation
48
  SIGNEXTEND,               ///< extend length of signed integer
49
50
  LT = 0x10,                ///< less-than comparison
51
  GT,                       ///< greater-than comparison
52
  SLT,                      ///< signed less-than comparison
53
  SGT,                      ///< signed greater-than comparison
54
  EQ,                       ///< equality comparison
55
  ISZERO,                   ///< simple not operator
56
  AND,                      ///< bitwise AND operation
57
  OR,                       ///< bitwise OR operation
58
  XOR,                      ///< bitwise XOR operation
59
  NOT,                      ///< bitwise NOT operation
60
  BYTE,                     ///< retrieve single byte from word
61
  SHL,                      ///< bitwise SHL operation
62
  SHR,                      ///< bitwise SHR operation
63
  SAR,                      ///< bitwise SAR operation
64
65
  KECCAK256 = 0x20,         ///< compute KECCAK-256 hash
66
67
  ADDRESS = 0x30,           ///< get address of currently executing account
68
  BALANCE,                  ///< get balance of the given account
69
  ORIGIN,                   ///< get execution origination address
70
  CALLER,                   ///< get caller address
71
  CALLVALUE,                ///< get deposited value by the instruction/transaction responsible for this execution
72
  CALLDATALOAD,             ///< get input data of current environment
73
  CALLDATASIZE,             ///< get size of input data in current environment
74
  CALLDATACOPY,             ///< copy input data in current environment to memory
75
  CODESIZE,                 ///< get size of code running in current environment
76
  CODECOPY,                 ///< copy code running in current environment to memory
77
  GASPRICE,                 ///< get price of gas in current environment
78
  EXTCODESIZE,              ///< get external code size (from another contract)
79
  EXTCODECOPY,              ///< copy external code (from another contract)
80
  RETURNDATASIZE = 0x3d,    ///< get size of return data buffer
81
  RETURNDATACOPY = 0x3e,    ///< copy return data in current environment to memory
82
  EXTCODEHASH = 0x3f,       ///< get external code hash (from another contract)
83
84
  BLOCKHASH = 0x40,         ///< get hash of most recent complete block
85
  COINBASE,                 ///< get the block's coinbase address
86
  TIMESTAMP,                ///< get the block's timestamp
87
  NUMBER,                   ///< get the block's number
88
  PREVRANDAO,               ///< get randomness provided by the beacon chain
89
  GASLIMIT,                 ///< get the block's gas limit
90
  CHAINID,                  ///< get the config's chainid param
91
  SELFBALANCE,              ///< get balance of the current account
92
  BASEFEE,                  ///< get the block's basefee
93
  BLOBHASH = 0x49,          ///< get a versioned hash of one of the blobs associated with the transaction
94
  BLOBBASEFEE = 0x4a,       ///< get the block's blob basefee
95
96
  POP = 0x50,               ///< remove item from stack
97
  MLOAD,                    ///< load word from memory
98
  MSTORE,                   ///< save word to memory
99
  MSTORE8,                  ///< save byte to memory
100
  SLOAD,                    ///< load word from storage
101
  SSTORE,                   ///< save word to storage
102
  JUMP,                     ///< alter the program counter
103
  JUMPI,                    ///< conditionally alter the program counter
104
  PC,                       ///< get the program counter
105
  MSIZE,                    ///< get the size of active memory
106
  GAS,                      ///< get the amount of available gas
107
  JUMPDEST,                 ///< set a potential jump destination
108
  TLOAD = 0x5c,             ///< load word from transient storage
109
  TSTORE = 0x5d,            ///< save word to transient storage
110
  MCOPY = 0x5e,             ///< copy between memory areas
111
112
  PUSH0 = 0x5f,             ///< place the value 0 on stack
113
  PUSH1 = 0x60,             ///< place 1 byte item on stack
114
  PUSH2,                    ///< place 2 byte item on stack
115
  PUSH3,                    ///< place 3 byte item on stack
116
  PUSH4,                    ///< place 4 byte item on stack
117
  PUSH5,                    ///< place 5 byte item on stack
118
  PUSH6,                    ///< place 6 byte item on stack
119
  PUSH7,                    ///< place 7 byte item on stack
120
  PUSH8,                    ///< place 8 byte item on stack
121
  PUSH9,                    ///< place 9 byte item on stack
122
  PUSH10,                   ///< place 10 byte item on stack
123
  PUSH11,                   ///< place 11 byte item on stack
124
  PUSH12,                   ///< place 12 byte item on stack
125
  PUSH13,                   ///< place 13 byte item on stack
126
  PUSH14,                   ///< place 14 byte item on stack
127
  PUSH15,                   ///< place 15 byte item on stack
128
  PUSH16,                   ///< place 16 byte item on stack
129
  PUSH17,                   ///< place 17 byte item on stack
130
  PUSH18,                   ///< place 18 byte item on stack
131
  PUSH19,                   ///< place 19 byte item on stack
132
  PUSH20,                   ///< place 20 byte item on stack
133
  PUSH21,                   ///< place 21 byte item on stack
134
  PUSH22,                   ///< place 22 byte item on stack
135
  PUSH23,                   ///< place 23 byte item on stack
136
  PUSH24,                   ///< place 24 byte item on stack
137
  PUSH25,                   ///< place 25 byte item on stack
138
  PUSH26,                   ///< place 26 byte item on stack
139
  PUSH27,                   ///< place 27 byte item on stack
140
  PUSH28,                   ///< place 28 byte item on stack
141
  PUSH29,                   ///< place 29 byte item on stack
142
  PUSH30,                   ///< place 30 byte item on stack
143
  PUSH31,                   ///< place 31 byte item on stack
144
  PUSH32,                   ///< place 32 byte item on stack
145
146
  DUP1 = 0x80,              ///< copies the highest item in the stack to the top of the stack
147
  DUP2,                     ///< copies the second highest item in the stack to the top of the stack
148
  DUP3,                     ///< copies the third highest item in the stack to the top of the stack
149
  DUP4,                     ///< copies the 4th highest item in the stack to the top of the stack
150
  DUP5,                     ///< copies the 5th highest item in the stack to the top of the stack
151
  DUP6,                     ///< copies the 6th highest item in the stack to the top of the stack
152
  DUP7,                     ///< copies the 7th highest item in the stack to the top of the stack
153
  DUP8,                     ///< copies the 8th highest item in the stack to the top of the stack
154
  DUP9,                     ///< copies the 9th highest item in the stack to the top of the stack
155
  DUP10,                    ///< copies the 10th highest item in the stack to the top of the stack
156
  DUP11,                    ///< copies the 11th highest item in the stack to the top of the stack
157
  DUP12,                    ///< copies the 12th highest item in the stack to the top of the stack
158
  DUP13,                    ///< copies the 13th highest item in the stack to the top of the stack
159
  DUP14,                    ///< copies the 14th highest item in the stack to the top of the stack
160
  DUP15,                    ///< copies the 15th highest item in the stack to the top of the stack
161
  DUP16,                    ///< copies the 16th highest item in the stack to the top of the stack
162
163
  SWAP1 = 0x90,             ///< swaps the highest and second highest value on the stack
164
  SWAP2,                    ///< swaps the highest and third highest value on the stack
165
  SWAP3,                    ///< swaps the highest and 4th highest value on the stack
166
  SWAP4,                    ///< swaps the highest and 5th highest value on the stack
167
  SWAP5,                    ///< swaps the highest and 6th highest value on the stack
168
  SWAP6,                    ///< swaps the highest and 7th highest value on the stack
169
  SWAP7,                    ///< swaps the highest and 8th highest value on the stack
170
  SWAP8,                    ///< swaps the highest and 9th highest value on the stack
171
  SWAP9,                    ///< swaps the highest and 10th highest value on the stack
172
  SWAP10,                   ///< swaps the highest and 11th highest value on the stack
173
  SWAP11,                   ///< swaps the highest and 12th highest value on the stack
174
  SWAP12,                   ///< swaps the highest and 13th highest value on the stack
175
  SWAP13,                   ///< swaps the highest and 14th highest value on the stack
176
  SWAP14,                   ///< swaps the highest and 15th highest value on the stack
177
  SWAP15,                   ///< swaps the highest and 16th highest value on the stack
178
  SWAP16,                   ///< swaps the highest and 17th highest value on the stack
179
180
  LOG0 = 0xa0,              ///< Makes a log entry; no topics.
181
  LOG1,                     ///< Makes a log entry; 1 topic.
182
  LOG2,                     ///< Makes a log entry; 2 topics.
183
  LOG3,                     ///< Makes a log entry; 3 topics.
184
  LOG4,                     ///< Makes a log entry; 4 topics.
185
186
  DATALOADN = 0xd1,         ///< load data from EOF data section
187
188
  RJUMP = 0xe0,             ///< relative jump
189
  RJUMPI = 0xe1,            ///< conditional relative jump
190
  CALLF = 0xe3,             ///< call function in a EOF code section
191
  RETF = 0xe4,              ///< return to caller from the code section of EOF container
192
  JUMPF = 0xe5,             ///< jump to a code section of EOF container without adding a new return stack frame.
193
  DUPN = 0xe6,              ///< copies a value at the stack depth given as immediate argument to the top of the stack
194
  SWAPN = 0xe7,             ///< swaps the highest value with a value at a stack depth given as immediate argument
195
  EOFCREATE = 0xec,         ///< create a new account with associated container code.
196
  RETURNCONTRACT = 0xee,    ///< return container to be deployed with axiliary data filled in.
197
  CREATE = 0xf0,            ///< create a new account with associated code
198
  CALL,                     ///< message-call into an account
199
  CALLCODE,                 ///< message-call with another account's code only
200
  RETURN,                   ///< halt execution returning output data
201
  DELEGATECALL,             ///< like CALLCODE but keeps caller's value and sender
202
  CREATE2 = 0xf5,           ///< create new account with associated code at address `sha3(0xff + sender + salt + init code) % 2**160`
203
  EXTCALL = 0xf8,           ///< EOF message-call into an account
204
  EXTDELEGATECALL = 0xf9,   ///< EOF delegate call
205
  STATICCALL = 0xfa,        ///< like CALL but disallow state modifications
206
  EXTSTATICCALL = 0xfb,     ///< like EXTCALL but disallow state modifications
207
208
  REVERT = 0xfd,            ///< halt execution, revert state and return output data
209
  INVALID = 0xfe,           ///< invalid instruction for expressing runtime errors (e.g., division-by-zero)
210
  SELFDESTRUCT = 0xff       ///< halt execution and register account for later deletion
211
};
212
213
/// @returns true if the instruction is of the CALL opcode family
214
constexpr bool isCallInstruction(Instruction _inst) noexcept
215
0
{
216
0
  switch (_inst)
217
0
  {
218
0
    case Instruction::CALL:
219
0
    case Instruction::CALLCODE:
220
0
    case Instruction::DELEGATECALL:
221
0
    case Instruction::STATICCALL:
222
0
    case Instruction::EXTCALL:
223
0
    case Instruction::EXTSTATICCALL:
224
0
    case Instruction::EXTDELEGATECALL:
225
0
      return true;
226
0
    default:
227
0
      return false;
228
0
  }
229
0
}
230
231
/// @returns true if the instruction is a PUSH
232
inline bool isPushInstruction(Instruction _inst)
233
31.5M
{
234
31.5M
  return Instruction::PUSH0 <= _inst && _inst <= Instruction::PUSH32;
235
31.5M
}
236
237
/// @returns true if the instruction is a LOG
238
inline bool isLogInstruction(Instruction _inst)
239
0
{
240
0
  return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4;
241
0
}
242
243
/// @returns the number of PUSH Instruction _inst
244
inline unsigned getPushNumber(Instruction _inst)
245
0
{
246
0
  return static_cast<uint8_t>(_inst) - unsigned(Instruction::PUSH0);
247
0
}
248
249
/// @returns the number of LOG Instruction _inst
250
inline unsigned getLogNumber(Instruction _inst)
251
0
{
252
0
  return static_cast<uint8_t>(_inst) - unsigned(Instruction::LOG0);
253
0
}
254
255
/// @returns the PUSH<_number> instruction
256
inline Instruction pushInstruction(unsigned _number)
257
15.4M
{
258
15.4M
  solAssert(_number <= 32);
259
15.4M
  return Instruction(unsigned(Instruction::PUSH0) + _number);
260
15.4M
}
261
262
/// @returns the DUP<_number> instruction
263
inline Instruction dupInstruction(unsigned _number)
264
5.14M
{
265
5.14M
  solAssert(1 <= _number && _number <= 16);
266
5.14M
  return Instruction(unsigned(Instruction::DUP1) + _number - 1);
267
5.14M
}
268
269
/// @returns the SWAP<_number> instruction
270
inline Instruction swapInstruction(unsigned _number)
271
16.1M
{
272
16.1M
  solAssert(1 <= _number && _number <= 16);
273
16.1M
  return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
274
16.1M
}
275
276
/// @returns the LOG<_number> instruction
277
inline Instruction logInstruction(unsigned _number)
278
422
{
279
422
  solAssert(_number <= 4);
280
422
  return Instruction(unsigned(Instruction::LOG0) + _number);
281
422
}
282
283
/// Gas price tiers representing static cost of an instruction.
284
/// Opcodes whose cost is dynamic or depends on EVM version should use the `Special` tier and need
285
/// dedicated logic in GasMeter (especially in estimateMax()).
286
/// The tiers loosely follow opcode groups originally defined in the Yellow Paper.
287
enum class Tier
288
{
289
  // NOTE: Tiers should be ordered by cost, since we sometimes perform comparisons between them.
290
  Zero = 0,   // 0, Zero
291
  Base,       // 2, Quick
292
  RJump,      // 2, RJump
293
  VeryLow,    // 3, Fastest
294
  RetF,       // 3,
295
  RJumpI,     // 4,
296
  Low,        // 5, Fast
297
  CallF,      // 5,
298
  JumpF,      // 5,
299
  Mid,        // 8, Mid
300
  High,       // 10, Slow
301
  BlockHash,  // 20
302
  WarmAccess, // 100, Warm Access
303
  Special,    // multiparam or otherwise special
304
  Invalid,    // Invalid.
305
};
306
307
/// Information structure for a particular instruction.
308
struct InstructionInfo
309
{
310
  std::string name;   ///< The name of the instruction.
311
  int additional;     ///< Additional items required in memory for this instructions (only for PUSH).
312
  int args;           ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
313
  int ret;            ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
314
  bool sideEffects;   ///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack
315
  Tier gasPriceTier;  ///< Tier for gas pricing.
316
};
317
318
/// Information on all the instructions.
319
InstructionInfo instructionInfo(Instruction _inst, langutil::EVMVersion _evmVersion);
320
321
/// check whether instructions exists.
322
bool isValidInstruction(Instruction _inst);
323
324
/// Convert from string mnemonic to Instruction type.
325
extern const std::map<std::string, Instruction, std::less<>> c_instructions;
326
327
}