/* 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 . */ /** @file Instruction.h * @author Gav Wood * @date 2014 */ #pragma once #include #include #include #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 c_instructions; /// Iterate through EVM code and call a function on each instruction. void eachInstruction(bytes const& _mem, std::function const& _onInstruction); /// Convert from EVM code to simple EVM assembly language. std::string disassemble(bytes const& _mem); } }