Fixing py-solc-x usage to automatically download or compile correct solc binary and use it (#1425)

* Fixed cases where multiple versions of solc is needed on the system, and the default version installed isn't the version required.

* Fixed setup.py

* black

* Bump semver requirement

* Put mythril_disassembler.py version check into util.py

* Pruning ethereum/util.py

* Provide for cases where --solv is used with a v before the version.
pull/1426/head
jim zhou 4 years ago committed by GitHub
parent c635015032
commit a5ac7dcdaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 43
      mythril/ethereum/util.py
  2. 38
      mythril/mythril/mythril_disassembler.py
  3. 4
      requirements.txt
  4. 4
      setup.py

@ -4,13 +4,15 @@ import binascii
import json import json
import sys import sys
import os import os
import platform
from pathlib import Path from pathlib import Path
from subprocess import PIPE, Popen from subprocess import PIPE, Popen
import solc
from ethereum.abi import encode_abi, encode_int, method_id from ethereum.abi import encode_abi, encode_int, method_id
from ethereum.utils import zpad from ethereum.utils import zpad
from mythril.exceptions import CompilerError from mythril.exceptions import CompilerError
from semantic_version import Version
if sys.version_info[1] >= 6: if sys.version_info[1] >= 6:
import solcx import solcx
@ -124,7 +126,30 @@ def solc_exists(version):
""" """
solc_binaries = [] solc_binaries = []
if version.startswith("0.4"): default_binary = "/usr/bin/solc"
if sys.version_info[1] >= 6:
if platform.system() == "Darwin":
solcx.import_installed_solc()
installed = solcx.get_installed_solc_versions()
if "v" + version in installed:
solcx.set_solc_version("v" + version)
solc_binary = solcx.install.get_executable()
return solc_binary
else:
available = solcx.get_available_solc_versions()
if "v" + version in available:
solcx.install_solc("v" + version)
solcx.set_solc_version("v" + version)
solc_binary = solcx.install.get_executable()
return solc_binary
elif Version("0.4.2") <= Version(version) <= Version("0.4.9"):
return None
elif Version("0.4.2") <= Version(version) <= Version("0.4.25"):
if not solc.main.is_solc_available():
solc.install_solc("v" + version)
solc_binary = solc.install.get_executable_path("v" + version)
return solc_binary
else:
solc_binaries = [ solc_binaries = [
os.path.join( os.path.join(
os.environ.get("HOME", str(Path.home())), os.environ.get("HOME", str(Path.home())),
@ -135,14 +160,8 @@ def solc_exists(version):
for solc_path in solc_binaries: for solc_path in solc_binaries:
if os.path.exists(solc_path): if os.path.exists(solc_path):
return solc_path return solc_path
elif sys.version_info[1] >= 6: elif os.path.exists(default_binary):
# we are using solc-x for the the 0.5 and higher
try:
return solcx.install.get_executable(version)
except SolcNotInstalled:
pass
# Last resort is to use the system installation
default_binary = "/usr/bin/solc"
if os.path.exists(default_binary):
return default_binary return default_binary
else:
return None

@ -3,6 +3,7 @@ import re
import solc import solc
import sys import sys
import os import os
import platform
from ethereum import utils from ethereum import utils
from typing import List, Tuple, Optional from typing import List, Tuple, Optional
@ -54,7 +55,13 @@ class MythrilDisassembler:
return os.environ.get("SOLC") or "solc" return os.environ.get("SOLC") or "solc"
# tried converting input to semver, seemed not necessary so just slicing for now # tried converting input to semver, seemed not necessary so just slicing for now
main_version = solc.main.get_solc_version_string() main_version = solc.get_solc_version_string()
# In case instead of just the version number, --solv v0.x.x is used
if version.startswith("v"):
version = version[1:]
main_version_number = re.match(r"\d+.\d+.\d+", main_version) main_version_number = re.match(r"\d+.\d+.\d+", main_version)
if main_version is None: if main_version is None:
raise CriticalError( raise CriticalError(
@ -65,35 +72,20 @@ class MythrilDisassembler:
solc_binary = os.environ.get("SOLC") or "solc" solc_binary = os.environ.get("SOLC") or "solc"
else: else:
solc_binary = util.solc_exists(version) solc_binary = util.solc_exists(version)
if solc_binary and solc_binary != util.solc_exists( if solc_binary is None:
"default_ubuntu_version" if sys.version_info[1] >= 6:
):
log.info("Given version is already installed")
else:
if version.startswith("0.4"):
try:
solc.install_solc("v" + version)
except solc.exceptions.SolcError:
raise CriticalError( raise CriticalError(
"There was an error when trying to install the specified solc version" "The version of solc that is needed cannot be installed automatically"
) )
elif sys.version_info[1] >= 6: elif sys.version_info[1] == 5:
# solcx supports python 3.6+
try:
solcx.install_solc("v" + version)
except solcx.exceptions.SolcError:
raise CriticalError( raise CriticalError(
"There was an error when trying to install the specified solc version" "Py-Solc doesn't support 0.5.*+. You can switch to python 3.6 which uses solcx."
) )
else: else:
raise CriticalError( raise CriticalError(
"Py-Solc doesn't support 0.5.*. You can switch to python 3.6 which uses solcx." "There was an error when trying to install the specified solc version"
) )
else:
solc_binary = util.solc_exists(version)
if not solc_binary:
raise solc.exceptions.SolcError()
log.info("Setting the compiler to %s", solc_binary) log.info("Setting the compiler to %s", solc_binary)
return solc_binary return solc_binary

@ -18,14 +18,14 @@ persistent>=4.2.0
plyvel plyvel
py-flags py-flags
py-evm==0.3.0a13 py-evm==0.3.0a13
py-solc-x==0.10.0 py-solc-x==0.10.1
py-solc py-solc
pytest>=3.6.0 pytest>=3.6.0
pytest-cov pytest-cov
pytest_mock pytest_mock
requests>=2.22.0 requests>=2.22.0
rlp>=1.0.1 rlp>=1.0.1
semantic_version==2.8.1 semantic_version==2.8.5
transaction>=2.2.1 transaction>=2.2.1
z3-solver>=4.8.5.0 z3-solver>=4.8.5.0
pysha3 pysha3

@ -30,8 +30,8 @@ REQUIRED = [
"z3-solver>=4.8.5.0", "z3-solver>=4.8.5.0",
"requests>=2.22.0", "requests>=2.22.0",
"py-solc", "py-solc",
"py-solc-x==0.6.0", "py-solc-x==0.10.1",
"semantic_version==2.8.1", "semantic_version==2.8.5",
"plyvel", "plyvel",
"eth_abi==1.3.0", "eth_abi==1.3.0",
"eth-account>=0.1.0a2,<=0.3.0", "eth-account>=0.1.0a2,<=0.3.0",

Loading…
Cancel
Save