Skip to content

Commit

Permalink
Merge pull request #1383 from mariuspod/feat/solc_use_latest_patch
Browse files Browse the repository at this point in the history
feat: adding a use_latest_patch option to solc compiler config
  • Loading branch information
iamdefinitelyahuman authored Jan 17, 2022
2 parents 202c43d + ffec657 commit c3dd4a7
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased](https://github.com/eth-brownie/brownie)
### Changed
- Force files to be opened as UTF-8
- Added a new solidity compiler setting `use_latest_patch` in brownie-config.yaml to use the latest patch version of a compiler based on the pragma version of the contract.
- Add cli flag `-r` for raising exceptions to the caller instead of doing a system exit.

## [1.17.2](https://github.com/eth-brownie/brownie/tree/v1.17.2) - 2021-12-04
Expand Down
38 changes: 36 additions & 2 deletions brownie/network/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from vvm import get_installable_vyper_versions
from vvm.utils.convert import to_vyper_version

from brownie._config import BROWNIE_FOLDER, CONFIG, REQUEST_HEADERS
from brownie._config import BROWNIE_FOLDER, CONFIG, REQUEST_HEADERS, _load_project_compiler_config
from brownie.convert.datatypes import Wei
from brownie.convert.normalize import format_input, format_output
from brownie.convert.utils import (
Expand Down Expand Up @@ -1088,7 +1088,8 @@ def from_explorer(
is_compilable = False
else:
try:
version = Version(compiler_str.lstrip("v")).truncate()
version = cls.get_solc_version(compiler_str, address)

is_compilable = (
version >= Version("0.4.22")
and version
Expand Down Expand Up @@ -1174,6 +1175,39 @@ def from_explorer(
_add_deployment(self)
return self

@classmethod
def get_solc_version(cls, compiler_str: str, address: str) -> Version:
"""
Return the solc compiler version either from the passed compiler string
or try to find the latest available patch semver compiler version.
Arguments
---------
compiler_str: str
The compiler string passed from the contract metadata.
address: str
The contract address to check for.
"""
version = Version(compiler_str.lstrip("v")).truncate()

compiler_config = _load_project_compiler_config(Path(os.getcwd()))
solc_config = compiler_config["solc"]
if "use_latest_patch" in solc_config:
use_latest_patch = solc_config["use_latest_patch"]
needs_patch_version = False
if isinstance(use_latest_patch, bool):
needs_patch_version = use_latest_patch
elif isinstance(use_latest_patch, list):
needs_patch_version = address in use_latest_patch

if needs_patch_version:
versions = [Version(str(i)) for i in solcx.get_installable_solc_versions()]
for v in filter(lambda l: l < version.next_minor(), versions):
if v > version:
version = v

return version

def set_alias(self, alias: Optional[str]) -> None:
"""
Apply a unique alias this object. The alias can be used to restore the
Expand Down
17 changes: 17 additions & 0 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,23 @@ Compiler settings. See :ref:`compiler settings<compile_settings>` for more infor
- zeppelin=/usr/local/lib/open-zeppelin/contracts/
- github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/
.. py:attribute:: use_latest_patch
Optional boolean or array contract list to use the latest patch semver compiler version. E.g. the if the contract has pragma version `0.4.16` and the latest available patch for `0.4` is `0.4.22` it will use this instead for compilations.

Enable for all contracts:
.. code-block:: yaml
compiler:
solc:
use_latest_patch: true
Enable for only specific contracts:
.. code-block:: yaml
compiler:
solc:
use_latest_patch:
- '0x514910771AF9Ca656af840dff83E8264EcF986CA'
.. py:attribute:: compiler.vyper
Settings specific to the Vyper compiler.
Expand Down
61 changes: 61 additions & 0 deletions tests/network/contract/test_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import pytest
import requests
import yaml
from semantic_version import Version

from brownie import Wei
from brownie.exceptions import BrownieCompilerWarning, BrownieEnvironmentWarning, ContractNotFound
Expand Down Expand Up @@ -308,6 +310,65 @@ def test_as_proxy_for(network):
assert proxy.address != implementation.address


def test_solc_use_latest_patch_true(testproject, network):
network.connect("mainnet")
solc_config = {"compiler": {"solc": {"use_latest_patch": True}}}
with testproject._path.joinpath("brownie-config.yaml").open("w") as fp:
yaml.dump(solc_config, fp)

assert Contract.get_solc_version(
"v0.4.16", "0x514910771AF9Ca656af840dff83E8264EcF986CA"
) == Version("0.4.26")


def test_solc_use_latest_patch_false(testproject, network):
network.connect("mainnet")
solc_config = {"compiler": {"solc": {"use_latest_patch": False}}}
with testproject._path.joinpath("brownie-config.yaml").open("w") as fp:
yaml.dump(solc_config, fp)

assert Contract.get_solc_version(
"v0.4.16", "0x514910771AF9Ca656af840dff83E8264EcF986CA"
) == Version("0.4.16")


def test_solc_use_latest_patch_missing(testproject, network):
network.connect("mainnet")
solc_config = {"compiler": {"solc": {}}}
with testproject._path.joinpath("brownie-config.yaml").open("w") as fp:
yaml.dump(solc_config, fp)

assert Contract.get_solc_version(
"v0.4.16", "0x514910771AF9Ca656af840dff83E8264EcF986CA"
) == Version("0.4.16")


def test_solc_use_latest_patch_specific_not_included(testproject, network):
network.connect("mainnet")
solc_config = {
"compiler": {"solc": {"use_latest_patch": ["0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e"]}}
}
with testproject._path.joinpath("brownie-config.yaml").open("w") as fp:
yaml.dump(solc_config, fp)

assert Contract.get_solc_version(
"v0.4.16", "0x514910771AF9Ca656af840dff83E8264EcF986CA"
) == Version("0.4.16")


def test_solc_use_latest_patch_specific_included(testproject, network):
network.connect("mainnet")
solc_config = {
"compiler": {"solc": {"use_latest_patch": ["0x514910771AF9Ca656af840dff83E8264EcF986CA"]}}
}
with testproject._path.joinpath("brownie-config.yaml").open("w") as fp:
yaml.dump(solc_config, fp)

assert Contract.get_solc_version(
"v0.4.16", "0x514910771AF9Ca656af840dff83E8264EcF986CA"
) == Version("0.4.26")


# @pytest.mark.parametrize(
# "original",
# [
Expand Down

0 comments on commit c3dd4a7

Please sign in to comment.