mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			269 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
	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 solidity
 | 
						|
{
 | 
						|
 | 
						|
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);
 | 
						|
 | 
						|
}
 | 
						|
}
 |