aboutsummaryrefslogtreecommitdiffstats
path: root/libevmasm/Instruction.h
blob: 2d415c08ba753a7ee58eb013f4c9896c09a42025 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Instruction.h
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#pragma once

#include <functional>
#include <libdevcore/Common.h>
#include <libdevcore/Assertions.h>
#include "Exceptions.h"

namespace dev
{
namespace eth
{

DEV_SIMPLE_EXCEPTION(InvalidDeposit);
DEV_SIMPLE_EXCEPTION(InvalidOpcode);

/// Virtual machine bytecode instruction.
enum class Instruction: uint8_t
{
    STOP = 0x00,        ///< halts execution
    ADD,                ///< addition operation
    MUL,                ///< mulitplication operation
    SUB,                ///< subtraction operation
    DIV,                ///< integer division operation
    SDIV,               ///< signed integer division operation
    MOD,                ///< modulo remainder operation
    SMOD,               ///< signed modulo remainder operation
    ADDMOD,             ///< unsigned modular addition
    MULMOD,             ///< unsigned modular multiplication
    EXP,                ///< exponential operation
    SIGNEXTEND,         ///< extend length of signed integer

    LT = 0x10,          ///< less-than comparision
    GT,                 ///< greater-than comparision
    SLT,                ///< signed less-than comparision
    SGT,                ///< signed greater-than comparision
    EQ,                 ///< equality comparision
    ISZERO,             ///< simple not operator
    AND,                ///< bitwise AND operation
    OR,                 ///< bitwise OR operation
    XOR,                ///< bitwise XOR operation
    NOT,                ///< bitwise NOT opertation
    BYTE,               ///< retrieve single byte from word

    SHA3 = 0x20,        ///< compute SHA3-256 hash

    ADDRESS = 0x30,     ///< get address of currently executing account
    BALANCE,            ///< get balance of the given account
    ORIGIN,             ///< get execution origination address
    CALLER,             ///< get caller address
    CALLVALUE,          ///< get deposited value by the instruction/transaction responsible for this execution
    CALLDATALOAD,       ///< get input data of current environment
    CALLDATASIZE,       ///< get size of input data in current environment
    CALLDATACOPY,       ///< copy input data in current environment to memory
    CODESIZE,           ///< get size of code running in current environment
    CODECOPY,           ///< copy code running in current environment to memory
    GASPRICE,           ///< get price of gas in current environment
    EXTCODESIZE,        ///< get external code size (from another contract)
    EXTCODECOPY,        ///< copy external code (from another contract)

    BLOCKHASH = 0x40,   ///< get hash of most recent complete block
    COINBASE,           ///< get the block's coinbase address
    TIMESTAMP,          ///< get the block's timestamp
    NUMBER,             ///< get the block's number
    DIFFICULTY,         ///< get the block's difficulty
    GASLIMIT,           ///< get the block's gas limit

    POP = 0x50,         ///< remove item from stack
    MLOAD,              ///< load word from memory
    MSTORE,             ///< save word to memory
    MSTORE8,            ///< save byte to memory
    SLOAD,              ///< load word from storage
    SSTORE,             ///< save word to storage
    JUMP,               ///< alter the program counter
    JUMPI,              ///< conditionally alter the program counter
    PC,                 ///< get the program counter
    MSIZE,              ///< get the size of active memory
    GAS,                ///< get the amount of available gas
    JUMPDEST,           ///< set a potential jump destination

    PUSH1 = 0x60,       ///< place 1 byte item on stack
    PUSH2,              ///< place 2 byte item on stack
    PUSH3,              ///< place 3 byte item on stack
    PUSH4,              ///< place 4 byte item on stack
    PUSH5,              ///< place 5 byte item on stack
    PUSH6,              ///< place 6 byte item on stack
    PUSH7,              ///< place 7 byte item on stack
    PUSH8,              ///< place 8 byte item on stack
    PUSH9,              ///< place 9 byte item on stack
    PUSH10,             ///< place 10 byte item on stack
    PUSH11,             ///< place 11 byte item on stack
    PUSH12,             ///< place 12 byte item on stack
    PUSH13,             ///< place 13 byte item on stack
    PUSH14,             ///< place 14 byte item on stack
    PUSH15,             ///< place 15 byte item on stack
    PUSH16,             ///< place 16 byte item on stack
    PUSH17,             ///< place 17 byte item on stack
    PUSH18,             ///< place 18 byte item on stack
    PUSH19,             ///< place 19 byte item on stack
    PUSH20,             ///< place 20 byte item on stack
    PUSH21,             ///< place 21 byte item on stack
    PUSH22,             ///< place 22 byte item on stack
    PUSH23,             ///< place 23 byte item on stack
    PUSH24,             ///< place 24 byte item on stack
    PUSH25,             ///< place 25 byte item on stack
    PUSH26,             ///< place 26 byte item on stack
    PUSH27,             ///< place 27 byte item on stack
    PUSH28,             ///< place 28 byte item on stack
    PUSH29,             ///< place 29 byte item on stack
    PUSH30,             ///< place 30 byte item on stack
    PUSH31,             ///< place 31 byte item on stack
    PUSH32,             ///< place 32 byte item on stack

    DUP1 = 0x80,        ///< copies the highest item in the stack to the top of the stack
    DUP2,               ///< copies the second highest item in the stack to the top of the stack
    DUP3,               ///< copies the third highest item in the stack to the top of the stack
    DUP4,               ///< copies the 4th highest item in the stack to the top of the stack
    DUP5,               ///< copies the 5th highest item in the stack to the top of the stack
    DUP6,               ///< copies the 6th highest item in the stack to the top of the stack
    DUP7,               ///< copies the 7th highest item in the stack to the top of the stack
    DUP8,               ///< copies the 8th highest item in the stack to the top of the stack
    DUP9,               ///< copies the 9th highest item in the stack to the top of the stack
    DUP10,              ///< copies the 10th highest item in the stack to the top of the stack
    DUP11,              ///< copies the 11th highest item in the stack to the top of the stack
    DUP12,              ///< copies the 12th highest item in the stack to the top of the stack
    DUP13,              ///< copies the 13th highest item in the stack to the top of the stack
    DUP14,              ///< copies the 14th highest item in the stack to the top of the stack
    DUP15,              ///< copies the 15th highest item in the stack to the top of the stack
    DUP16,              ///< copies the 16th highest item in the stack to the top of the stack

    SWAP1 = 0x90,       ///< swaps the highest and second highest value on the stack
    SWAP2,              ///< swaps the highest and third highest value on the stack
    SWAP3,              ///< swaps the highest and 4th highest value on the stack
    SWAP4,              ///< swaps the highest and 5th highest value on the stack
    SWAP5,              ///< swaps the highest and 6th highest value on the stack
    SWAP6,              ///< swaps the highest and 7th highest value on the stack
    SWAP7,              ///< swaps the highest and 8th highest value on the stack
    SWAP8,              ///< swaps the highest and 9th highest value on the stack
    SWAP9,              ///< swaps the highest and 10th highest value on the stack
    SWAP10,             ///< swaps the highest and 11th highest value on the stack
    SWAP11,             ///< swaps the highest and 12th highest value on the stack
    SWAP12,             ///< swaps the highest and 13th highest value on the stack
    SWAP13,             ///< swaps the highest and 14th highest value on the stack
    SWAP14,             ///< swaps the highest and 15th highest value on the stack
    SWAP15,             ///< swaps the highest and 16th highest value on the stack
    SWAP16,             ///< swaps the highest and 17th highest value on the stack

    LOG0 = 0xa0,        ///< Makes a log entry; no topics.
    LOG1,               ///< Makes a log entry; 1 topic.
    LOG2,               ///< Makes a log entry; 2 topics.
    LOG3,               ///< Makes a log entry; 3 topics.
    LOG4,               ///< Makes a log entry; 4 topics.

    CREATE = 0xf0,      ///< create a new account with associated code
    CALL,               ///< message-call into an account
    CALLCODE,           ///< message-call with another account's code only
    RETURN,             ///< halt execution returning output data
    DELEGATECALL,       ///< like CALLCODE but keeps caller's value and sender
    SUICIDE = 0xff      ///< halt execution and register account for later deletion
};

/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
    return (byte)_inst - unsigned(Instruction::PUSH1) + 1;
}

/// @returns the number of DUP Instruction _inst
inline unsigned getDupNumber(Instruction _inst)
{
    return (byte)_inst - unsigned(Instruction::DUP1) + 1;
}

/// @returns the number of SWAP Instruction _inst
inline unsigned getSwapNumber(Instruction _inst)
{
    return (byte)_inst - unsigned(Instruction::SWAP1) + 1;
}

/// @returns the PUSH<_number> instruction
inline Instruction pushInstruction(unsigned _number)
{
    assertThrow(1 <= _number && _number <= 32, InvalidOpcode, "Invalid PUSH instruction requested.");
    return Instruction(unsigned(Instruction::PUSH1) + _number - 1);
}

/// @returns the DUP<_number> instruction
inline Instruction dupInstruction(unsigned _number)
{
    assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid DUP instruction requested.");
    return Instruction(unsigned(Instruction::DUP1) + _number - 1);
}

/// @returns the SWAP<_number> instruction
inline Instruction swapInstruction(unsigned _number)
{
    assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid SWAP instruction requested.");
    return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
}

/// @returns the LOG<_number> instruction
inline Instruction logInstruction(unsigned _number)
{
    assertThrow(_number <= 4, InvalidOpcode, "Invalid LOG instruction requested.");
    return Instruction(unsigned(Instruction::LOG0) + _number);
}

enum Tier
{
    ZeroTier = 0,   // 0, Zero
    BaseTier,       // 2, Quick
    VeryLowTier,    // 3, Fastest
    LowTier,        // 5, Fast
    MidTier,        // 8, Mid
    HighTier,       // 10, Slow
    ExtTier,        // 20, Ext
    SpecialTier,    // multiparam or otherwise special
    InvalidTier     // Invalid.
};

/// Information structure for a particular instruction.
struct InstructionInfo
{
    std::string name;   ///< The name of the instruction.
    int additional;     ///< Additional items required in memory for this instructions (only for PUSH).
    int args;           ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
    int ret;            ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
    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
    int gasPriceTier;   ///< Tier for gas pricing.
};

/// Information on all the instructions.
InstructionInfo instructionInfo(Instruction _inst);

/// check whether instructions exists
bool isValidInstruction(Instruction _inst);

/// Convert from string mnemonic to Instruction type.
extern const std::map<std::string, Instruction> c_instructions;

/// Iterate through EVM code and call a function on each instruction.
void eachInstruction(bytes const& _mem, std::function<void(Instruction,u256 const&)> const& _onInstruction);

/// Convert from EVM code to simple EVM assembly language.
std::string disassemble(bytes const& _mem);

}
}