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. 61
      mythril/ethereum/util.py
  2. 48
      mythril/mythril/mythril_disassembler.py
  3. 4
      requirements.txt
  4. 4
      setup.py

@ -4,13 +4,15 @@ import binascii
import json
import sys
import os
import platform
from pathlib import Path
from subprocess import PIPE, Popen
import solc
from ethereum.abi import encode_abi, encode_int, method_id
from ethereum.utils import zpad
from mythril.exceptions import CompilerError
from semantic_version import Version
if sys.version_info[1] >= 6:
import solcx
@ -124,25 +126,42 @@ def solc_exists(version):
"""
solc_binaries = []
if version.startswith("0.4"):
solc_binaries = [
os.path.join(
os.environ.get("HOME", str(Path.home())),
".py-solc/solc-v" + version,
"bin/solc",
) # py-solc setup
]
for solc_path in solc_binaries:
if os.path.exists(solc_path):
return solc_path
elif sys.version_info[1] >= 6:
# 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):
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 = [
os.path.join(
os.environ.get("HOME", str(Path.home())),
".py-solc/solc-v" + version,
"bin/solc",
) # py-solc setup
]
for solc_path in solc_binaries:
if os.path.exists(solc_path):
return solc_path
elif os.path.exists(default_binary):
return default_binary
else:
return None

@ -3,6 +3,7 @@ import re
import solc
import sys
import os
import platform
from ethereum import utils
from typing import List, Tuple, Optional
@ -54,7 +55,13 @@ class MythrilDisassembler:
return os.environ.get("SOLC") or "solc"
# 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)
if main_version is None:
raise CriticalError(
@ -65,36 +72,21 @@ class MythrilDisassembler:
solc_binary = os.environ.get("SOLC") or "solc"
else:
solc_binary = util.solc_exists(version)
if solc_binary and solc_binary != util.solc_exists(
"default_ubuntu_version"
):
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(
"There was an error when trying to install the specified solc version"
)
elif sys.version_info[1] >= 6:
# solcx supports python 3.6+
try:
solcx.install_solc("v" + version)
except solcx.exceptions.SolcError:
raise CriticalError(
"There was an error when trying to install the specified solc version"
)
if solc_binary is None:
if sys.version_info[1] >= 6:
raise CriticalError(
"The version of solc that is needed cannot be installed automatically"
)
elif sys.version_info[1] == 5:
raise CriticalError(
"Py-Solc doesn't support 0.5.*+. You can switch to python 3.6 which uses solcx."
)
else:
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"
)
solc_binary = util.solc_exists(version)
if not solc_binary:
raise solc.exceptions.SolcError()
log.info("Setting the compiler to %s", solc_binary)
else:
log.info("Setting the compiler to %s", solc_binary)
return solc_binary

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

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

Loading…
Cancel
Save