Refactor opcode files and fix issues (#1532)

pull/1534/head
Nikhil Parasaram 3 years ago committed by GitHub
parent 579480b477
commit 9d922fe9f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      mythril/analysis/module/modules/exceptions.py
  2. 4
      mythril/analysis/module/modules/suicide.py
  3. 4
      mythril/analysis/module/util.py
  4. 1
      mythril/analysis/security.py
  5. 17
      mythril/disassembler/asm.py
  6. 186
      mythril/laser/ethereum/instruction_data.py
  7. 4
      mythril/laser/ethereum/instructions.py
  8. 9
      mythril/laser/ethereum/svm.py
  9. 230
      mythril/support/opcodes.py
  10. 2
      tests/instructions/static_call_test.py

@ -35,7 +35,7 @@ class Exceptions(DetectionModule):
swc_id = ASSERT_VIOLATION
description = "Checks whether any exception states are reachable."
entry_point = EntryPoint.CALLBACK
pre_hooks = ["ASSERT_FAIL", "JUMP", "REVERT"]
pre_hooks = ["INVALID", "JUMP", "REVERT"]
def _execute(self, state: GlobalState) -> None:
"""

@ -28,7 +28,7 @@ class AccidentallyKillable(DetectionModule):
swc_id = UNPROTECTED_SELFDESTRUCT
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK
pre_hooks = ["SUICIDE"]
pre_hooks = ["SELFDESTRUCT"]
def __init__(self):
super().__init__()
@ -61,7 +61,7 @@ class AccidentallyKillable(DetectionModule):
to = state.mstate.stack[-1]
log.debug("SUICIDE in function %s", state.environment.active_function_name)
log.debug("SELFDESTRUCT in function %s", state.environment.active_function_name)
description_head = "Any sender can cause the contract to self-destruct."

@ -2,12 +2,12 @@ from collections import defaultdict
from typing import List, Optional, Callable, Mapping, Dict
import logging
from mythril.support.opcodes import opcodes
from mythril.support.opcodes import OPCODES
from mythril.analysis.module.base import DetectionModule, EntryPoint
from mythril.analysis.module.loader import ModuleLoader
log = logging.getLogger(__name__)
OP_CODE_LIST = [c[0] for _, c in opcodes.items()]
OP_CODE_LIST = OPCODES.keys()
def get_detection_module_hooks(

@ -1,7 +1,6 @@
"""This module contains functionality for hooking in detection modules and
executing them."""
from mythril.support.opcodes import opcodes
from mythril.analysis.module import ModuleLoader, reset_callback_modules
from mythril.analysis.module.base import EntryPoint
from mythril.analysis.report import Issue

@ -4,13 +4,10 @@ code disassembly."""
import re
from collections import Generator
from mythril.support.opcodes import opcodes
from mythril.support.opcodes import OPCODES, ADDRESS, ADDRESS_OPCODE_MAPPING
regex_PUSH = re.compile(r"^PUSH(\d*)$")
# Additional mnemonic to catch failed assertions
opcodes[254] = ("ASSERT_FAIL", 0, 0, 0)
class EvmInstruction:
"""Model to hold the information of the disassembly."""
@ -54,9 +51,8 @@ def get_opcode_from_name(operation_name: str) -> int:
:param operation_name:
:return:
"""
for op_code, value in opcodes.items():
if operation_name == value[0]:
return op_code
if operation_name in OPCODES:
return OPCODES[operation_name][ADDRESS]
raise RuntimeError("Unknown opcode")
@ -105,16 +101,15 @@ def disassemble(bytecode: bytes) -> list:
while address < length:
try:
op_code = opcodes[bytecode[address]]
op_code = ADDRESS_OPCODE_MAPPING[bytecode[address]]
except KeyError:
instruction_list.append(EvmInstruction(address, "INVALID"))
address += 1
continue
op_code_name = op_code[0]
current_instruction = EvmInstruction(address, op_code_name)
current_instruction = EvmInstruction(address, op_code)
match = re.search(regex_PUSH, op_code_name)
match = re.search(regex_PUSH, op_code)
if match:
argument_bytes = bytecode[address + 1 : address + 1 + int(match.group(1))]
current_instruction.argument = "0x" + argument_bytes.hex()

@ -1,191 +1,7 @@
from ethereum import opcodes
from ethereum.utils import ceil32
from typing import Callable, Dict, Tuple, Union
Z_OPERATOR_TUPLE = (0, 1)
UN_OPERATOR_TUPLE = (1, 1)
BIN_OPERATOR_TUPLE = (2, 1)
T_OPERATOR_TUPLE = (3, 1)
GAS = "gas"
STACK = "stack"
# Gas tuple contains (min_gas, max_gas)
# stack tuple contains (no_of_elements_popped, no_of_elements_pushed)
OPCODES = {
"STOP": {GAS: (0, 0), STACK: (0, 0)},
"ADD": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"MUL": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"SUB": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"DIV": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"SDIV": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"MOD": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"SMOD": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"ADDMOD": {GAS: (8, 8), STACK: BIN_OPERATOR_TUPLE},
"MULMOD": {GAS: (8, 8), STACK: T_OPERATOR_TUPLE},
"EXP": {GAS: (10, 340), STACK: BIN_OPERATOR_TUPLE}, # exponent max 2^32
"SIGNEXTEND": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE},
"LT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"GT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SLT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SGT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"EQ": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"AND": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"ISZERO": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE},
"OR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"XOR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"NOT": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE},
"BYTE": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SHL": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SHR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SAR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE},
"SHA3": {
GAS: (
30,
30 + 6 * 8,
), # max can be larger, but usually storage location with 8 words
STACK: BIN_OPERATOR_TUPLE,
},
"ADDRESS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"BALANCE": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE},
"ORIGIN": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLVALUE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLDATALOAD": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE},
"CALLDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLDATACOPY": {
GAS: (2, 2 + 3 * 768), # https://ethereum.stackexchange.com/a/47556
STACK: (3, 0),
},
"CODESIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CODECOPY": {
GAS: (2, 2 + 3 * 768), # https://ethereum.stackexchange.com/a/47556,
STACK: (3, 0),
},
"GASPRICE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"EXTCODESIZE": {GAS: (700, 700), STACK: Z_OPERATOR_TUPLE},
"EXTCODECOPY": {
GAS: (700, 700 + 3 * 768), # https://ethereum.stackexchange.com/a/47556
STACK: (4, 0),
},
"EXTCODEHASH": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE},
"RETURNDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"RETURNDATACOPY": {GAS: (3, 3), STACK: (3, 0)},
"BLOCKHASH": {GAS: (20, 20), STACK: UN_OPERATOR_TUPLE},
"COINBASE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"TIMESTAMP": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"NUMBER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"DIFFICULTY": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"GASLIMIT": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CHAINID": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"SELFBALANCE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"POP": {GAS: (2, 2), STACK: (1, 0)},
# assume 1KB memory r/w cost as upper bound
"MLOAD": {GAS: (3, 96), STACK: UN_OPERATOR_TUPLE},
"MSTORE": {GAS: (3, 98), STACK: (2, 0)},
"MSTORE8": {GAS: (3, 98), STACK: (2, 0)},
# assume 64 byte r/w cost as upper bound
"SLOAD": {GAS: (800, 800), STACK: UN_OPERATOR_TUPLE},
"SSTORE": {GAS: (5000, 25000), STACK: (1, 0)},
"JUMP": {GAS: (8, 8), STACK: (1, 0)},
"JUMPI": {GAS: (10, 10), STACK: (2, 0)},
"PC": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"MSIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"GAS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"JUMPDEST": {GAS: (1, 1), STACK: (0, 0)},
"PUSH1": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH2": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH3": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH4": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH5": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH6": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH7": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH8": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH9": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH10": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH11": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH12": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH13": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH14": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH15": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH16": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH17": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH18": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH19": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH20": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH21": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH22": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH23": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH24": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH25": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH26": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH27": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH28": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH29": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH30": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH31": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"PUSH32": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP1": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP2": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP3": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP4": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP5": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP6": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP7": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP8": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP9": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP10": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP11": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP12": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP13": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP14": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP15": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"DUP16": {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE},
"SWAP1": {GAS: (3, 3), STACK: (0, 0)},
"SWAP2": {GAS: (3, 3), STACK: (0, 0)},
"SWAP3": {GAS: (3, 3), STACK: (0, 0)},
"SWAP4": {GAS: (3, 3), STACK: (0, 0)},
"SWAP5": {GAS: (3, 3), STACK: (0, 0)},
"SWAP6": {GAS: (3, 3), STACK: (0, 0)},
"SWAP7": {GAS: (3, 3), STACK: (0, 0)},
"SWAP8": {GAS: (3, 3), STACK: (0, 0)},
"SWAP9": {GAS: (3, 3), STACK: (0, 0)},
"SWAP10": {GAS: (3, 3), STACK: (0, 0)},
"SWAP11": {GAS: (3, 3), STACK: (0, 0)},
"SWAP12": {GAS: (3, 3), STACK: (0, 0)},
"SWAP13": {GAS: (3, 3), STACK: (0, 0)},
"SWAP14": {GAS: (3, 3), STACK: (0, 0)},
"SWAP15": {GAS: (3, 3), STACK: (0, 0)},
"SWAP16": {GAS: (3, 3), STACK: (0, 0)},
# apparently Solidity only allows byte32 as input to the log
# function. Virtually it could be as large as the block gas limit
# allows, but let's stick to the reasonable standard here.
# https://ethereum.stackexchange.com/a/1691
"LOG0": {GAS: (375, 375 + 8 * 32), STACK: (2, 0)},
"LOG1": {GAS: (2 * 375, 2 * 375 + 8 * 32), STACK: (3, 0)},
"LOG2": {GAS: (3 * 375, 3 * 375 + 8 * 32), STACK: (4, 0)},
"LOG3": {GAS: (4 * 375, 4 * 375 + 8 * 32), STACK: (5, 0)},
"LOG4": {GAS: (5 * 375, 5 * 375 + 8 * 32), STACK: (6, 0)},
"CREATE": {GAS: (32000, 32000), STACK: T_OPERATOR_TUPLE},
"CREATE2": {
GAS: (32000, 32000), # TODO: Make the gas values dynamic
STACK: (4, 1),
},
"CALL": {GAS: (700, 700 + 9000 + 25000), STACK: (7, 1)},
"CALLCODE": {GAS: (700, 700 + 9000 + 25000), STACK: (7, 1)},
"RETURN": {GAS: (0, 0), STACK: (2, 0)},
"BASEFEE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"DELEGATECALL": {GAS: (700, 700 + 9000 + 25000), STACK: (6, 1)},
"STATICCALL": {GAS: (700, 700 + 9000 + 25000), STACK: (6, 1)},
"REVERT": {GAS: (0, 0), STACK: (2, 0)},
"SUICIDE": {GAS: (5000, 30000), STACK: (1, 0)},
"ASSERT_FAIL": {GAS: (0, 0), STACK: (0, 0)},
"INVALID": {GAS: (0, 0), STACK: (0, 0)},
"BEGINSUB": {GAS: (2, 2), STACK: (0, 0)},
"JUMPSUB": {GAS: (10, 10), STACK: (1, 0)},
"RETURNSUB": {GAS: (5, 5), STACK: (0, 0)},
} # type: Dict[str, Dict[str, Tuple[int, int]]]
from mythril.support.opcodes import OPCODES, STACK, GAS
def calculate_sha3_gas(length: int):

@ -1850,14 +1850,14 @@ class Instruction:
global_state.current_transaction.end(global_state, return_data)
@StateTransition(is_state_mutation_instruction=True)
def suicide_(self, global_state: GlobalState):
def selfdestruct_(self, global_state: GlobalState):
"""
:param global_state:
"""
target = global_state.mstate.stack.pop()
transfer_amount = global_state.environment.active_account.balance()
# Often the target of the suicide instruction will be symbolic
# Often the target of the selfdestruct instruction will be symbolic
# If it isn't then we'll transfer the balance to the indicated contract
global_state.world_state.balances[target] += transfer_amount

@ -5,7 +5,7 @@ from copy import copy
from datetime import datetime, timedelta
from typing import Callable, Dict, DefaultDict, List, Tuple, Optional
from mythril.support.opcodes import opcodes as OPCODES
from mythril.support.opcodes import OPCODES
from mythril.analysis.potential_issues import check_potential_issues
from mythril.laser.execution_info import ExecutionInfo
from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
@ -110,7 +110,7 @@ class LaserEVM:
self.iprof = iprof
self.instr_pre_hook = {} # type: Dict[str, List[Callable]]
self.instr_post_hook = {} # type: Dict[str, List[Callable]]
for op, _, _, _ in OPCODES.values():
for op in OPCODES:
self.instr_pre_hook[op] = []
self.instr_post_hook[op] = []
log.info("LASER EVM initialized with dynamic loader: " + str(dynamic_loader))
@ -261,7 +261,6 @@ class LaserEVM:
for state in new_states
if state.world_state.constraints.is_possible
]
self.manage_cfg(op_code, new_states) # TODO: What about op_code is None?
if new_states:
self.work_list += new_states
@ -598,13 +597,13 @@ class LaserEVM:
"""Registers instructions hooks from plugins"""
if hook_type == "pre":
if opcode is None:
for op, _, _, _ in OPCODES.values():
for op in OPCODES:
self.instr_pre_hook[op].append(hook(op))
else:
self.instr_pre_hook[opcode].append(hook)
else:
if opcode is None:
for op, _, _, _ in OPCODES.values():
for op in OPCODES:
self.instr_post_hook[op].append(hook(op))
else:
self.instr_post_hook[opcode].append(hook)

@ -1,100 +1,144 @@
# This pyethereum opcodes file with added opcodes
from typing import Dict, Tuple
from typing import Dict, Tuple, Union
opcodes = {
0x00: ("STOP", 0, 0, 0),
0x01: ("ADD", 2, 1, 3),
0x02: ("MUL", 2, 1, 5),
0x03: ("SUB", 2, 1, 3),
0x04: ("DIV", 2, 1, 5),
0x05: ("SDIV", 2, 1, 5),
0x06: ("MOD", 2, 1, 5),
0x07: ("SMOD", 2, 1, 5),
0x08: ("ADDMOD", 3, 1, 8),
0x09: ("MULMOD", 3, 1, 8),
0x0A: ("EXP", 2, 1, 10),
0x0B: ("SIGNEXTEND", 2, 1, 5),
0x10: ("LT", 2, 1, 3),
0x11: ("GT", 2, 1, 3),
0x12: ("SLT", 2, 1, 3),
0x13: ("SGT", 2, 1, 3),
0x14: ("EQ", 2, 1, 3),
0x15: ("ISZERO", 1, 1, 3),
0x16: ("AND", 2, 1, 3),
0x17: ("OR", 2, 1, 3),
0x18: ("XOR", 2, 1, 3),
0x19: ("NOT", 1, 1, 3),
0x1A: ("BYTE", 2, 1, 3),
0x1B: ("SHL", 2, 1, 3),
0x1C: ("SHR", 2, 1, 3),
0x1D: ("SAR", 2, 1, 3),
0x20: ("SHA3", 2, 1, 30),
0x30: ("ADDRESS", 0, 1, 2),
0x31: ("BALANCE", 1, 1, 20), # now 400
0x32: ("ORIGIN", 0, 1, 2),
0x33: ("CALLER", 0, 1, 2),
0x34: ("CALLVALUE", 0, 1, 2),
0x35: ("CALLDATALOAD", 1, 1, 3),
0x36: ("CALLDATASIZE", 0, 1, 2),
0x37: ("CALLDATACOPY", 3, 0, 3),
0x38: ("CODESIZE", 0, 1, 2),
0x39: ("CODECOPY", 3, 0, 3),
0x3A: ("GASPRICE", 0, 1, 2),
0x3B: ("EXTCODESIZE", 1, 1, 20), # now 700
0x3C: ("EXTCODECOPY", 4, 0, 20), # now 700
0x3D: ("RETURNDATASIZE", 0, 1, 2),
0x3E: ("RETURNDATACOPY", 3, 0, 3),
0x3F: ("EXTCODEHASH", 3, 0, 3),
0x40: ("BLOCKHASH", 1, 1, 20),
0x41: ("COINBASE", 0, 1, 2),
0x42: ("TIMESTAMP", 0, 1, 2),
0x43: ("NUMBER", 0, 1, 2),
0x44: ("DIFFICULTY", 0, 1, 2),
0x45: ("GASLIMIT", 0, 1, 2),
0x46: ("CHAINID", 0, 1, 2),
0x47: ("SELFBALANCE", 0, 1, 5),
0x48: ("BASEFEE", 0, 1, 2),
0x50: ("POP", 1, 0, 2),
0x51: ("MLOAD", 1, 1, 3),
0x52: ("MSTORE", 2, 0, 3),
0x53: ("MSTORE8", 2, 0, 3),
0x54: ("SLOAD", 1, 1, 50), # 200 now
0x55: ("SSTORE", 2, 0, 0),
0x56: ("JUMP", 1, 0, 8),
0x57: ("JUMPI", 2, 0, 10),
0x58: ("PC", 0, 1, 2),
0x59: ("MSIZE", 0, 1, 2),
0x5A: ("GAS", 0, 1, 2),
0x5B: ("JUMPDEST", 0, 0, 1),
0x5C: ("BEGINSUB", 0, 0, 2),
0x5D: ("RETURNSUB", 0, 0, 5),
0x5E: ("JUMPSUB", 1, 0, 10),
0xA0: ("LOG0", 2, 0, 375),
0xA1: ("LOG1", 3, 0, 750),
0xA2: ("LOG2", 4, 0, 1125),
0xA3: ("LOG3", 5, 0, 1500),
0xA4: ("LOG4", 6, 0, 1875),
0xF0: ("CREATE", 3, 1, 32000),
0xF1: ("CALL", 7, 1, 40), # 700 now
0xF2: ("CALLCODE", 7, 1, 40), # 700 now
0xF3: ("RETURN", 2, 0, 0),
0xF4: ("DELEGATECALL", 6, 1, 40), # 700 now
0xF5: ("CREATE2", 3, 1, 32000),
0xFA: ("STATICCALL", 6, 1, 40),
0xFD: ("REVERT", 2, 0, 0),
0xFF: ("SUICIDE", 1, 0, 0), # 5000 now
} # type: Dict[int, Tuple[str, int, int, int]]
opcodesMetropolis = {0x3D, 0x3E, 0xFA, 0xFD}
Z_OPERATOR_TUPLE = (0, 1)
UN_OPERATOR_TUPLE = (1, 1)
BIN_OPERATOR_TUPLE = (2, 1)
T_OPERATOR_TUPLE = (3, 1)
GAS = "gas"
STACK = "stack"
ADDRESS = "address"
# Gas tuple contains (min_gas, max_gas)
# stack tuple contains (no_of_elements_popped, no_of_elements_pushed)
# TODO: Make this more specific when TypedDict supports key re-usage.
OPCODES: Dict = {
"STOP": {GAS: (0, 0), STACK: (0, 0), ADDRESS: 0x00},
"ADD": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x01},
"MUL": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x02},
"SUB": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x03},
"DIV": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x04},
"SDIV": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x05},
"MOD": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x06},
"SMOD": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x07},
"ADDMOD": {GAS: (8, 8), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x08},
"MULMOD": {GAS: (8, 8), STACK: T_OPERATOR_TUPLE, ADDRESS: 0x09},
"EXP": {
GAS: (10, 340),
STACK: BIN_OPERATOR_TUPLE,
ADDRESS: 0x0A,
}, # exponent max 2^32
"SIGNEXTEND": {GAS: (5, 5), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x0B},
"LT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x10},
"GT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x11},
"SLT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x12},
"SGT": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x13},
"EQ": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x14},
"ISZERO": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x15},
"AND": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x16},
"OR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x17},
"XOR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x18},
"NOT": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x19},
"BYTE": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x1A},
"SHL": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x1B},
"SHR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x1C},
"SAR": {GAS: (3, 3), STACK: BIN_OPERATOR_TUPLE, ADDRESS: 0x1D},
"SHA3": {
GAS: (
30,
30 + 6 * 8,
), # max can be larger, but usually storage location with 8 words
STACK: BIN_OPERATOR_TUPLE,
ADDRESS: 0x20,
},
"ADDRESS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x30},
"BALANCE": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x31},
"ORIGIN": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x32},
"CALLER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x33},
"CALLVALUE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x34},
"CALLDATALOAD": {GAS: (3, 3), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x35},
"CALLDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x36},
"CALLDATACOPY": {
GAS: (2, 2 + 3 * 768), # https://ethereum.stackexchange.com/a/47556
STACK: (3, 0),
ADDRESS: 0x37,
},
"CODESIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x38},
"CODECOPY": {
GAS: (2, 2 + 3 * 768), # https://ethereum.stackexchange.com/a/47556,
STACK: (3, 0),
ADDRESS: 0x39,
},
"GASPRICE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x3A},
"EXTCODESIZE": {GAS: (700, 700), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x3B},
"EXTCODECOPY": {
GAS: (700, 700 + 3 * 768), # https://ethereum.stackexchange.com/a/47556
STACK: (4, 0),
ADDRESS: 0x3C,
},
"EXTCODEHASH": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x3F},
"RETURNDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x3D},
"RETURNDATACOPY": {GAS: (3, 3), STACK: (3, 0), ADDRESS: 0x3E},
"BLOCKHASH": {GAS: (20, 20), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x40},
"COINBASE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x41},
"TIMESTAMP": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x42},
"NUMBER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x43},
"DIFFICULTY": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x44},
"GASLIMIT": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x45},
"CHAINID": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x46},
"SELFBALANCE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x47},
"BASEFEE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x48},
"POP": {GAS: (2, 2), STACK: (1, 0), ADDRESS: 0x50},
# assume 1KB memory r/w cost as upper bound
"MLOAD": {GAS: (3, 96), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x51},
"MSTORE": {GAS: (3, 98), STACK: (2, 0), ADDRESS: 0x52},
"MSTORE8": {GAS: (3, 98), STACK: (2, 0), ADDRESS: 0x53},
# assume 64 byte r/w cost as upper bound
"SLOAD": {GAS: (800, 800), STACK: UN_OPERATOR_TUPLE, ADDRESS: 0x54},
"SSTORE": {GAS: (5000, 25000), STACK: (1, 0), ADDRESS: 0x55},
"JUMP": {GAS: (8, 8), STACK: (1, 0), ADDRESS: 0x56},
"JUMPI": {GAS: (10, 10), STACK: (2, 0), ADDRESS: 0x57},
"PC": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x58},
"MSIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x59},
"GAS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x5A},
"JUMPDEST": {GAS: (1, 1), STACK: (0, 0), ADDRESS: 0x5B},
"BEGINSUB": {GAS: (2, 2), STACK: (0, 0), ADDRESS: 0x5C},
"RETURNSUB": {GAS: (5, 5), STACK: (0, 0), ADDRESS: 0x5D},
"JUMPSUB": {GAS: (10, 10), STACK: (1, 0), ADDRESS: 0x5E},
# apparently Solidity only allows byte32 as input to the log
# function. Virtually it could be as large as the block gas limit
# allows, but let's stick to the reasonable standard here.
# https://ethereum.stackexchange.com/a/1691
"LOG0": {GAS: (375, 375 + 8 * 32), STACK: (2, 0), ADDRESS: 0xA0},
"LOG1": {GAS: (2 * 375, 2 * 375 + 8 * 32), STACK: (3, 0), ADDRESS: 0xA1},
"LOG2": {GAS: (3 * 375, 3 * 375 + 8 * 32), STACK: (4, 0), ADDRESS: 0xA2},
"LOG3": {GAS: (4 * 375, 4 * 375 + 8 * 32), STACK: (5, 0), ADDRESS: 0xA3},
"LOG4": {GAS: (5 * 375, 5 * 375 + 8 * 32), STACK: (6, 0), ADDRESS: 0xA4},
"CREATE": {GAS: (32000, 32000), STACK: T_OPERATOR_TUPLE, ADDRESS: 0xF0},
"CREATE2": {
GAS: (32000, 32000), # TODO: Make the gas values dynamic
STACK: (4, 1),
ADDRESS: 0xF5,
},
"CALL": {GAS: (700, 700 + 9000 + 25000), STACK: (7, 1), ADDRESS: 0xF1},
"CALLCODE": {GAS: (700, 700 + 9000 + 25000), STACK: (7, 1), ADDRESS: 0xF2},
"RETURN": {GAS: (0, 0), STACK: (2, 0), ADDRESS: 0xF3},
"DELEGATECALL": {GAS: (700, 700 + 9000 + 25000), STACK: (6, 1), ADDRESS: 0xF4},
"STATICCALL": {GAS: (700, 700 + 9000 + 25000), STACK: (6, 1), ADDRESS: 0xFA},
"REVERT": {GAS: (0, 0), STACK: (2, 0), ADDRESS: 0xFD},
"SELFDESTRUCT": {GAS: (5000, 30000), STACK: (1, 0), ADDRESS: 0xFF},
"INVALID": {GAS: (0, 0), STACK: (0, 0), ADDRESS: 0xFE},
}
for i in range(1, 33):
opcodes[0x5F + i] = ("PUSH" + str(i), 0, 1, 3)
OPCODES[f"PUSH{i}"] = {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x5F + i}
for i in range(1, 17):
opcodes[0x7F + i] = ("DUP" + str(i), i, i + 1, 3)
opcodes[0x8F + i] = ("SWAP" + str(i), i + 1, i + 1, 3)
OPCODES[f"DUP{i}"] = {GAS: (3, 3), STACK: (0, 0), ADDRESS: 0x7F + i}
OPCODES[f"SWAP{i}"] = {GAS: (3, 3), STACK: Z_OPERATOR_TUPLE, ADDRESS: 0x8F + i}
ADDRESS_OPCODE_MAPPING = {}
reverse_opcodes = {}
for o in opcodes:
vars()[opcodes[o][0]] = opcodes[o]
reverse_opcodes[opcodes[o][0]] = o
for opcode, opcode_data in OPCODES.items():
ADDRESS_OPCODE_MAPPING[opcode_data[ADDRESS]] = opcode

@ -56,7 +56,7 @@ def test_staticcall(f1):
test_data = (
"suicide",
"selfdestruct",
"create",
"create2",
"log0",

Loading…
Cancel
Save