Merge branch 'develop' into feature/enable_detection_plugins

pull/1342/head
Bernhard Mueller 5 years ago committed by GitHub
commit b7cee9cd14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .circleci/config.yml
  2. 24
      docs/source/security-analysis.rst
  3. 2
      mythril/analysis/module/base.py
  4. 61
      mythril/analysis/module/loader.py
  5. 6
      mythril/analysis/module/module_helpers.py
  6. 4
      mythril/analysis/module/modules/arbitrary_jump.py
  7. 2
      mythril/analysis/module/modules/arbitrary_write.py
  8. 6
      mythril/analysis/module/modules/delegatecall.py
  9. 13
      mythril/analysis/module/modules/dependence_on_predictable_vars.py
  10. 6
      mythril/analysis/module/modules/deprecated_ops.py
  11. 2
      mythril/analysis/module/modules/ether_thief.py
  12. 6
      mythril/analysis/module/modules/exceptions.py
  13. 2
      mythril/analysis/module/modules/external_calls.py
  14. 6
      mythril/analysis/module/modules/integer.py
  15. 6
      mythril/analysis/module/modules/multiple_sends.py
  16. 10
      mythril/analysis/module/modules/state_change_external_calls.py
  17. 6
      mythril/analysis/module/modules/suicide.py
  18. 6
      mythril/analysis/module/modules/unchecked_retval.py
  19. 2
      mythril/analysis/module/modules/user_assertions.py
  20. 13
      mythril/ethereum/interface/rpc/client.py
  21. 7
      mythril/exceptions.py
  22. 38
      mythril/interfaces/cli.py
  23. 2
      mythril/laser/ethereum/keccak_function_manager.py
  24. 4
      mythril/mythril/mythril_analyzer.py
  25. 29
      mythril/mythril/mythril_config.py
  26. 17
      tests/mythril/mythril_config_test.py
  27. 4
      tox.ini

@ -54,9 +54,9 @@ jobs:
working_directory: /home/mythril
no_output_timeout: 10m
environment:
LC_ALL: en_US.ASCII
LANG: en_US.ASCII
MYTHRIL_DIR: '/home/mythril'
INFURA_ID: $INFURA_ID
- store_test_results:
path: /home/mythril/.tox/output

@ -57,15 +57,15 @@ Analyzing On-Chain Contracts
When analyzing contracts on the blockchain, Mythril will by default attempt to query INFURA. You can use the built-in INFURA support or manually configure the RPC settings with the :code:`--rpc` argument.
+--------------------------------+-------------------------------------------------+
| :code:`--rpc ganache` | Connect to local Ganache |
+--------------------------------+-------------------------------------------------+
| :code:`--rpc infura-[netname]` | Connect to mainnet, rinkeby, kovan, or ropsten. |
+--------------------------------+-------------------------------------------------+
| :code:`--rpc host:port` | Connect to custom rpc |
+--------------------------------+-------------------------------------------------+
| :code:`--rpctls <True/False>` | RPC connection over TLS (default: False) |
+--------------------------------+-------------------------------------------------+
+-------------------------------------------------+-------------------------------------------------+
| :code:`--rpc ganache` | Connect to local Ganache |
+-------------------------------------------------+-------------------------------------------------+
| :code:`--rpc infura-[netname] --infura-id <ID>` | Connect to mainnet, rinkeby, kovan, or ropsten. |
+-------------------------------------------------+-------------------------------------------------+
| :code:`--rpc host:port` | Connect to custom rpc |
+-------------------------------------------------+-------------------------------------------------+
| :code:`--rpctls <True/False>` | RPC connection over TLS (default: False) |
+-------------------------------------------------+-------------------------------------------------+
To specify a contract address, use :code:`-a <address>`
@ -73,13 +73,14 @@ Analyze mainnet contract via INFURA:
.. code-block:: bash
myth analyze -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd
myth analyze -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd --infura-id <ID>
You can also use the environment variable `INFURA_ID` instead of the cmd line argument or set it in ~/.mythril/config.ini.
Adding the :code:`-l` flag will cause mythril to automatically retrieve dependencies, such as dynamically linked library contracts:
.. code-block:: bash
myth -v4 analyze -l -a 0xEbFD99838cb0c132016B9E117563CB41f2B02264
myth -v4 analyze -l -a 0xEbFD99838cb0c132016B9E117563CB41f2B02264 --infura-id <ID>
******************
Speed vs. Coverage
@ -88,3 +89,4 @@ Speed vs. Coverage
The execution timeout can be specified with the :code:`--execution-timeout <seconds>` argument. When the timeout is reached, mythril will stop analysis and print out all currently found issues.
The maximum recursion depth for the symbolic execution engine can be controlled with the :code:`--max-depth` argument. The default value is 22. Lowering this value will decrease the number of explored states and analysis time, while increasing this number will increase the number of explored states and increase analysis time. For some contracts, it helps to fine tune this number to get the best analysis results.
-

@ -42,7 +42,7 @@ class DetectionModule(ABC):
- post_hooks: A list of instructions to hook the laser vm for (post execution of the instruction)
"""
name = "Detection Module Name"
name = "Detection Module Name / Title"
swc_id = "SWC-000"
description = "Detection module description"
entry_point = EntryPoint.CALLBACK # type: EntryPoint

@ -3,23 +3,27 @@ from mythril.support.support_utils import Singleton
from mythril.analysis.module.modules.arbitrary_jump import ArbitraryJump
from mythril.analysis.module.modules.arbitrary_write import ArbitraryStorage
from mythril.analysis.module.modules.delegatecall import DelegateCallModule
from mythril.analysis.module.modules.delegatecall import ArbitraryDelegateCall
from mythril.analysis.module.modules.dependence_on_predictable_vars import (
PredictableDependenceModule,
PredictableVariables,
)
from mythril.analysis.module.modules.deprecated_ops import DeprecatedOperationsModule
from mythril.analysis.module.modules.deprecated_ops import DeprecatedOperations
from mythril.analysis.module.modules.ether_thief import EtherThief
from mythril.analysis.module.modules.exceptions import ReachableExceptionsModule
from mythril.analysis.module.modules.exceptions import Exceptions
from mythril.analysis.module.modules.external_calls import ExternalCalls
from mythril.analysis.module.modules.integer import IntegerOverflowUnderflowModule
from mythril.analysis.module.modules.multiple_sends import MultipleSendsModule
from mythril.analysis.module.modules.state_change_external_calls import StateChange
from mythril.analysis.module.modules.suicide import SuicideModule
from mythril.analysis.module.modules.unchecked_retval import UncheckedRetvalModule
from mythril.analysis.module.modules.integer import IntegerArithmetics
from mythril.analysis.module.modules.multiple_sends import MultipleSends
from mythril.analysis.module.modules.state_change_external_calls import (
StateChangeAfterCall,
)
from mythril.analysis.module.modules.suicide import AccidentallyKillable
from mythril.analysis.module.modules.unchecked_retval import UncheckedRetval
from mythril.analysis.module.modules.user_assertions import UserAssertions
from mythril.analysis.module.base import EntryPoint
from mythril.exceptions import DetectorNotFoundError
from typing import Optional, List
@ -53,11 +57,28 @@ class ModuleLoader(object, metaclass=Singleton):
:param white_list: If specified: only return whitelisted detection modules
:return: The selected detection modules
"""
result = self._modules[:]
if white_list:
# Sanity check
available_names = [type(module).__name__ for module in result]
for name in white_list:
if name not in available_names:
raise DetectorNotFoundError(
"Invalid detection module: {}".format(name)
)
result = [
module for module in result if type(module).__name__ in white_list
]
if entry_point:
result = [module for module in result if module.entry_point == entry_point]
if white_list:
result = [module for module in result if module.name in white_list]
return result
def _register_mythril_modules(self):
@ -65,17 +86,17 @@ class ModuleLoader(object, metaclass=Singleton):
[
ArbitraryJump(),
ArbitraryStorage(),
DelegateCallModule(),
PredictableDependenceModule(),
DeprecatedOperationsModule(),
ArbitraryDelegateCall(),
PredictableVariables(),
DeprecatedOperations(),
EtherThief(),
ReachableExceptionsModule(),
Exceptions(),
ExternalCalls(),
IntegerOverflowUnderflowModule(),
MultipleSendsModule(),
StateChange(),
SuicideModule(),
UncheckedRetvalModule(),
IntegerArithmetics(),
MultipleSends(),
StateChangeAfterCall(),
AccidentallyKillable(),
UncheckedRetval(),
UserAssertions(),
]
)

@ -0,0 +1,6 @@
import traceback
def is_prehook() -> bool:
"""Check if we are in prehook. One of Bernhard's trademark hacks!"""
return "pre_hook" in traceback.format_stack()[-5]

@ -9,14 +9,14 @@ log = logging.getLogger(__name__)
DESCRIPTION = """
Search for any writes to an arbitrary storage slot
Search for jumps to arbitrary locations in the bytecode
"""
class ArbitraryJump(DetectionModule):
"""This module searches for JUMPs to an arbitrary instruction."""
name = "Jump to an arbitrary line"
name = "Jump to an arbitrary bytecode location"
swc_id = ARBITRARY_JUMP
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK

@ -21,7 +21,7 @@ Search for any writes to an arbitrary storage slot
class ArbitraryStorage(DetectionModule):
"""This module searches for a feasible write to an arbitrary storage slot."""
name = "Arbitrary Storage Write"
name = "Write to an arbitrary storage location"
swc_id = WRITE_TO_ARBITRARY_STORAGE
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK

@ -19,10 +19,10 @@ from mythril.laser.smt import symbol_factory, UGT
log = logging.getLogger(__name__)
class DelegateCallModule(DetectionModule):
class ArbitraryDelegateCall(DetectionModule):
"""This module detects calldata being forwarded using DELEGATECALL."""
name = "DELEGATECALL Usage in Fallback Function"
name = "Delegatecall to a user-specified address"
swc_id = DELEGATECALL_TO_UNTRUSTED_CONTRACT
description = (
"Check for invocations of delegatecall(msg.data) in the fallback function."
@ -100,4 +100,4 @@ class DelegateCallModule(DetectionModule):
return []
detector = DelegateCallModule()
detector = ArbitraryDelegateCall()

@ -9,10 +9,10 @@ from mythril.exceptions import UnsatError
from mythril.analysis import solver
from mythril.laser.smt import ULT, symbol_factory
from mythril.analysis.swc_data import TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS
from mythril.analysis.module.module_helpers import is_prehook
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.annotation import StateAnnotation
from typing import cast, List
import traceback
log = logging.getLogger(__name__)
@ -20,11 +20,6 @@ predictable_ops = ["COINBASE", "GASLIMIT", "TIMESTAMP", "NUMBER"]
final_ops = ["CALL", "SUICIDE", "STOP", "RETURN"]
def is_prehook() -> bool:
"""Check if we are in prehook. One of Bernhard's trademark hacks!"""
return "pre_hook" in traceback.format_stack()[-5]
class PredictableValueAnnotation:
"""Symbol annotation used if a variable is initialized from a predictable environment variable."""
@ -50,11 +45,11 @@ class OldBlockNumberUsedAnnotation(StateAnnotation):
pass
class PredictableDependenceModule(DetectionModule):
class PredictableVariables(DetectionModule):
"""This module detects whether control flow decisions are made using predictable
parameters."""
name = "Dependence of Predictable Variables"
name = "Control flow depends on a predictable environment variable"
swc_id = "{} {}".format(TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS)
description = (
"Check whether important control flow decisions are influenced by block.coinbase,"
@ -232,4 +227,4 @@ class PredictableDependenceModule(DetectionModule):
return issues
detector = PredictableDependenceModule()
detector = PredictableVariables()

@ -15,10 +15,10 @@ Check for usage of deprecated opcodes
"""
class DeprecatedOperationsModule(DetectionModule):
class DeprecatedOperations(DetectionModule):
"""This module checks for the usage of deprecated op codes."""
name = "Deprecated Operations"
name = "Usage of deprecated instructions"
swc_id = DEPRECATED_FUNCTIONS_USAGE
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK
@ -87,4 +87,4 @@ class DeprecatedOperationsModule(DetectionModule):
return [potential_issue]
detector = DeprecatedOperationsModule()
detector = DeprecatedOperations()

@ -36,7 +36,7 @@ class EtherThief(DetectionModule):
"""This module search for cases where Ether can be withdrawn to a user-
specified address."""
name = "Ether Thief"
name = "Attacker can profitably withdraw Ether from the contract account"
swc_id = UNPROTECTED_ETHER_WITHDRAWAL
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK

@ -11,10 +11,10 @@ from mythril.laser.ethereum.state.global_state import GlobalState
log = logging.getLogger(__name__)
class ReachableExceptionsModule(DetectionModule):
class Exceptions(DetectionModule):
""""""
name = "Reachable Exceptions"
name = "Exception or assertion violation"
swc_id = ASSERT_VIOLATION
description = "Checks whether any exception states are reachable."
entry_point = EntryPoint.CALLBACK
@ -76,4 +76,4 @@ class ReachableExceptionsModule(DetectionModule):
return []
detector = ReachableExceptionsModule()
detector = Exceptions()

@ -49,7 +49,7 @@ class ExternalCalls(DetectionModule):
"""This module searches for low level calls (e.g. call.value()) that
forward all gas to the callee."""
name = "External calls"
name = "External call to another contract"
swc_id = REENTRANCY
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK

@ -61,10 +61,10 @@ class OverUnderflowStateAnnotation(StateAnnotation):
return new_annotation
class IntegerOverflowUnderflowModule(DetectionModule):
class IntegerArithmetics(DetectionModule):
"""This module searches for integer over- and underflows."""
name = "Integer Overflow and Underflow"
name = "Integer overflow or underflow"
swc_id = INTEGER_OVERFLOW_AND_UNDERFLOW
description = (
"For every SUB instruction, check if there's a possible state "
@ -337,7 +337,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
self.issues.append(issue)
detector = IntegerOverflowUnderflowModule()
detector = IntegerArithmetics()
def _get_address_from_state(state):

@ -24,10 +24,10 @@ class MultipleSendsAnnotation(StateAnnotation):
return result
class MultipleSendsModule(DetectionModule):
class MultipleSends(DetectionModule):
"""This module checks for multiple sends in a single transaction."""
name = "Multiple Sends"
name = "Multiple external calls in the same transaction"
swc_id = MULTIPLE_SENDS
description = "Check for multiple sends in a single transaction"
entry_point = EntryPoint.CALLBACK
@ -98,4 +98,4 @@ class MultipleSendsModule(DetectionModule):
return []
detector = MultipleSendsModule()
detector = MultipleSends()

@ -95,11 +95,11 @@ class StateChangeCallsAnnotation(StateAnnotation):
)
class StateChange(DetectionModule):
class StateChangeAfterCall(DetectionModule):
"""This module searches for state change after low level calls (e.g. call.value()) that
forward gas to the callee."""
name = "State Change After External calls"
name = "State change after an external call"
swc_id = REENTRANCY
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK
@ -159,13 +159,13 @@ class StateChange(DetectionModule):
# Record state changes following from a transfer of ether
if op_code in CALL_LIST:
value = global_state.mstate.stack[-3] # type: BitVec
if StateChange._balance_change(value, global_state):
if StateChangeAfterCall._balance_change(value, global_state):
for annotation in annotations:
annotation.state_change_states.append(global_state)
# Record external calls
if op_code in CALL_LIST:
StateChange._add_external_call(global_state)
StateChangeAfterCall._add_external_call(global_state)
# Check for vulnerabilities
vulnerabilities = []
@ -195,4 +195,4 @@ class StateChange(DetectionModule):
return False
detector = StateChange()
detector = StateChangeAfterCall()

@ -20,11 +20,11 @@ For kill-able contracts, also check whether it is possible to direct the contrac
"""
class SuicideModule(DetectionModule):
class AccidentallyKillable(DetectionModule):
"""This module checks if the contact can be 'accidentally' killed by
anyone."""
name = "Unprotected Selfdestruct"
name = "Contract can be accidentally killed by anyone"
swc_id = UNPROTECTED_SELFDESTRUCT
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK
@ -109,4 +109,4 @@ class SuicideModule(DetectionModule):
return []
detector = SuicideModule()
detector = AccidentallyKillable()

@ -28,10 +28,10 @@ class UncheckedRetvalAnnotation(StateAnnotation):
return result
class UncheckedRetvalModule(DetectionModule):
class UncheckedRetval(DetectionModule):
"""A detection module to test whether CALL return value is checked."""
name = "Unchecked Return Value"
name = "Return value of an external call is not checked"
swc_id = UNCHECKED_RET_VAL
description = (
"Test whether CALL return value is checked. "
@ -121,4 +121,4 @@ class UncheckedRetvalModule(DetectionModule):
return []
detector = UncheckedRetvalModule()
detector = UncheckedRetval()

@ -28,7 +28,7 @@ assertion_failed_hash = (
class UserAssertions(DetectionModule):
"""This module searches for user supplied exceptions: emit AssertionFailed("Error")."""
name = "User assertions"
name = "A user-defined assertion has been triggered"
swc_id = ASSERT_VIOLATION
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK

@ -52,11 +52,20 @@ class EthJsonRpc(BaseClient):
:return:
"""
params = params or []
data = {"jsonrpc": "2.0", "method": method, "params": params, "id": _id}
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": _id,
}
scheme = "http"
if self.tls:
scheme += "s"
url = "{}://{}:{}".format(scheme, self.host, self.port)
if self.host:
url = "{}://{}:{}".format(scheme, self.host, self.port)
else:
url = "{}".format(scheme)
headers = {"Content-Type": JSON_MEDIA_TYPE}
log.debug("rpc send: %s" % json.dumps(data))
try:

@ -39,3 +39,10 @@ class AddressNotFoundError(MythrilBaseException):
found."""
pass
class DetectorNotFoundError(MythrilBaseException):
"""A Mythril exception denoting attempted usage of a non-existant
detection module."""
pass

@ -17,7 +17,11 @@ import traceback
import mythril.support.signatures as sigs
from argparse import ArgumentParser, Namespace, RawTextHelpFormatter
from mythril import mythx
from mythril.exceptions import AddressNotFoundError, CriticalError
from mythril.exceptions import (
AddressNotFoundError,
DetectorNotFoundError,
CriticalError,
)
from mythril.laser.ethereum.transaction.symbolic import ACTORS
from mythril.mythril import (
MythrilAnalyzer,
@ -25,6 +29,9 @@ from mythril.mythril import (
MythrilConfig,
MythrilLevelDB,
)
from mythril.analysis.module import ModuleLoader
from mythril.__version__ import __version__ as VERSION
ANALYZE_LIST = ("analyze", "a")
@ -42,6 +49,7 @@ COMMAND_LIST = (
"leveldb-search",
"function-to-hash",
"hash-to-address",
"list-detectors",
"version",
"truffle",
"help",
@ -225,6 +233,11 @@ def main() -> None:
)
create_pro_parser(pro_parser)
subparsers.add_parser(
"list-detectors",
parents=[output_parser],
help="Lists available detection modules",
)
read_storage_parser = subparsers.add_parser(
"read-storage",
help="Retrieves storage slots from a given address through rpc",
@ -374,6 +387,10 @@ def create_analyzer_parser(analyzer_parser: ArgumentParser):
action="store_true",
help="analyze a truffle project (run from project dir)",
)
commands.add_argument(
"--infura-id", help="set infura id for onchain analysis",
)
options = analyzer_parser.add_argument_group("options")
options.add_argument(
"-m",
@ -529,6 +546,8 @@ def set_config(args: Namespace):
:return: modified config
"""
config = MythrilConfig()
if args.__dict__.get("infura_id", None):
config.set_api_infura_id(args.infura_id)
if (
args.command in ANALYZE_LIST
and (args.dynld or not args.no_onchain_storage_access)
@ -729,9 +748,11 @@ def execute_command(
"markdown": report.as_markdown(),
}
print(outputs[args.outform])
except ModuleNotFoundError as e:
except DetectorNotFoundError as e:
exit_with_error(args.outform, format(e))
except CriticalError as e:
exit_with_error(
args.outform, "Error loading analysis modules: " + format(e)
args.outform, "Analysis error encountered: " + format(e)
)
else:
@ -772,6 +793,17 @@ def parse_args_and_execute(parser: ArgumentParser, args: Namespace) -> None:
print("Mythril version {}".format(VERSION))
sys.exit()
if args.command == "list-detectors":
modules = []
for module in ModuleLoader().get_detection_modules():
modules.append({"classname": type(module).__name__, "title": module.name})
if args.outform == "json":
print(json.dumps(modules))
else:
for module_data in modules:
print("{}: {}".format(module_data["classname"], module_data["title"]))
sys.exit()
if args.command == "help":
parser.print_help()
sys.exit()

@ -141,7 +141,7 @@ class KeccakFunctionManager:
)
concrete_cond = symbol_factory.Bool(False)
for key, keccak in self.concrete_hashes.items():
hash_eq = And(func(func_input) == keccak, key == func_input,)
hash_eq = And(func(func_input) == keccak, key == func_input)
concrete_cond = Or(concrete_cond, hash_eq)
return And(inv(func(func_input)) == func_input, Or(cond, concrete_cond))

@ -18,6 +18,7 @@ from mythril.analysis.report import Report, Issue
from mythril.ethereum.evmcontract import EVMContract
from mythril.laser.smt import SolverStatistics
from mythril.support.start_time import StartTime
from mythril.exceptions import DetectorNotFoundError
log = logging.getLogger(__name__)
@ -172,6 +173,9 @@ class MythrilAnalyzer:
custom_modules_directory=self.custom_modules_directory,
)
issues = fire_lasers(sym, modules)
except DetectorNotFoundError as e:
# Bubble up
raise e
except KeyboardInterrupt:
log.critical("Keyboard Interrupt")
if self.iprof is not None:

@ -23,6 +23,7 @@ class MythrilConfig:
"""
def __init__(self):
self.infura_id = os.getenv("INFURA_ID") # type: str
self.mythril_dir = self._init_mythril_dir()
self.config_path = os.path.join(self.mythril_dir, "config.ini")
self.leveldb_dir = None
@ -30,6 +31,9 @@ class MythrilConfig:
self.eth = None # type: Optional[EthJsonRpc]
self.eth_db = None # type: Optional[EthLevelDB]
def set_api_infura_id(self, id):
self.infura_id = id
@staticmethod
def _init_mythril_dir() -> str:
"""
@ -83,12 +87,17 @@ class MythrilConfig:
if not config.has_option("defaults", "dynamic_loading"):
self._add_dynamic_loading_option(config)
if not config.has_option("defaults", "infura_id"):
config.set("defaults", "infura_id", "")
with codecs.open(self.config_path, "w", "utf-8") as fp:
config.write(fp)
leveldb_dir = config.get(
"defaults", "leveldb_dir", fallback=leveldb_default_path
)
if not self.infura_id:
self.infura_id = config.get("defaults", "infura_id", fallback="")
self.leveldb_dir = os.path.expanduser(leveldb_dir)
@staticmethod
@ -167,7 +176,9 @@ class MythrilConfig:
def set_api_rpc_infura(self) -> None:
"""Set the RPC mode to INFURA on Mainnet."""
log.info("Using INFURA Main Net for RPC queries")
self.eth = EthJsonRpc("mainnet.infura.io", 443, True)
self.eth = EthJsonRpc(
"mainnet.infura.io/v3/{}".format(self.infura_id), None, True
)
def set_api_rpc(self, rpc: str = None, rpctls: bool = False) -> None:
"""
@ -178,8 +189,20 @@ class MythrilConfig:
rpcconfig = ("localhost", 7545, False)
else:
m = re.match(r"infura-(.*)", rpc)
if m and m.group(1) in ["mainnet", "rinkeby", "kovan", "ropsten"]:
rpcconfig = (m.group(1) + ".infura.io", 443, True)
if self.infura_id in (None, ""):
raise CriticalError(
"Infura key not provided. Use --infura-id <INFURA_ID> "
"or set it in the environment variable INFURA_ID "
"or in the ~/.mythril/config.ini file'"
)
rpcconfig = (
"{}.infura.io/v3/{}".format(m.group(1), self.infura_id),
None,
True,
)
else:
try:
host, port = rpc.split(":")
@ -191,7 +214,7 @@ class MythrilConfig:
if rpcconfig:
log.info("Using RPC settings: %s" % str(rpcconfig))
self.eth = EthJsonRpc(rpcconfig[0], int(rpcconfig[1]), rpcconfig[2])
self.eth = EthJsonRpc(rpcconfig[0], rpcconfig[1], rpcconfig[2])
else:
raise CriticalError("Invalid RPC settings, check help for details.")

@ -1,4 +1,5 @@
import pytest
import os
from configparser import ConfigParser
from pathlib import Path
@ -13,16 +14,15 @@ def test_config_path_dynloading():
Path(__file__).parent.parent / "testdata/mythril_config_inputs/config.ini"
)
config.set_api_from_config_path()
assert config.eth.host == "mainnet.infura.io"
assert config.eth.port == 443
assert "mainnet.infura.io/v3/" in config.eth.host
rpc_types_tests = [
("infura", "mainnet.infura.io", 443, True),
("ganache", "localhost", 7545, True),
("infura-rinkeby", "rinkeby.infura.io", 443, True),
("infura-ropsten", "ropsten.infura.io", 443, True),
("infura-kovan", "kovan.infura.io", 443, True),
("infura", "mainnet.infura.io/v3/", None, True),
("ganache", "localhost", None, True),
("infura-rinkeby", "rinkeby.infura.io/v3/", None, True),
("infura-ropsten", "ropsten.infura.io/v3/", None, True),
("infura-kovan", "kovan.infura.io/v3/", None, True),
("localhost", "localhost", 8545, True),
("localhost:9022", "localhost", 9022, True),
("pinfura", None, None, False),
@ -35,8 +35,7 @@ def test_set_rpc(rpc_type, host, port, success):
config = MythrilConfig()
if success:
config._set_rpc(rpc_type)
assert config.eth.host == host
assert config.eth.port == port
assert host in config.eth.host
else:
with pytest.raises(CriticalError):
config._set_rpc(rpc_type)

@ -5,7 +5,7 @@ envlist = py36
deps =
pytest
pytest-mock
passenv = MYTHRIL_DIR = {homedir}
passenv = MYTHRIL_DIR INFURA_ID
whitelist_externals = mkdir
commands =
mkdir -p {toxinidir}/tests/testdata/outputs_current/
@ -24,7 +24,7 @@ deps =
pytest
pytest-mock
pytest-cov
passenv = MYTHRIL_DIR = {homedir}
passenv = MYTHRIL_DIR INFURA_ID
whitelist_externals = mkdir
commands =
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional mythril

Loading…
Cancel
Save