예제 #1
0
def test_unknown_language():
    with pytest.raises(UnsupportedLanguage):
        compiler.generate_input_json({"foo": ""}, language="Bar")
    with pytest.raises(UnsupportedLanguage):
        compiler.compile_from_input_json({"language": "FooBar"})
    with pytest.raises(UnsupportedLanguage):
        compiler.generate_build_json({"language": "BarBaz"}, {})
예제 #2
0
def test_compile_optimizer(monkeypatch):
    def _test_compiler(a, **kwargs):
        assert kwargs['optimize'] is True
        assert kwargs['optimize_runs'] == 666
    monkeypatch.setattr('solcx.compile_standard', _test_compiler)
    input_json = {'settings': {'optimizer': {'enabled': True, 'runs': 666}}}
    compiler.compile_from_input_json(input_json)
    input_json = {'settings': {'optimizer': {'enabled': True, 'runs': 31337}}}
    with pytest.raises(AssertionError):
        compiler.compile_from_input_json(input_json)
    input_json = {'settings': {'optimizer': {'enabled': False, 'runs': 666}}}
    with pytest.raises(AssertionError):
        compiler.compile_from_input_json(input_json)
예제 #3
0
def test_compile_optimizer(monkeypatch):
    def _test_compiler(a, **kwargs):
        assert kwargs["optimize"] is True
        assert kwargs["optimize_runs"] == 666

    monkeypatch.setattr("solcx.compile_standard", _test_compiler)
    input_json = {"settings": {"optimizer": {"enabled": True, "runs": 666}}}
    compiler.compile_from_input_json(input_json)
    input_json = {"settings": {"optimizer": {"enabled": True, "runs": 31337}}}
    with pytest.raises(AssertionError):
        compiler.compile_from_input_json(input_json)
    input_json = {"settings": {"optimizer": {"enabled": False, "runs": 666}}}
    with pytest.raises(AssertionError):
        compiler.compile_from_input_json(input_json)
예제 #4
0
    def from_explorer(
        cls,
        address: str,
        as_proxy_for: Optional[str] = None,
        owner: Optional[AccountsType] = None,
        silent: bool = False,
    ) -> "Contract":
        """
        Create a new `Contract` object with source code queried from a block explorer.

        Arguments
        ---------
        address : str
            Address where the contract is deployed.
        as_proxy_for : str, optional
            Address of the implementation contract, if `address` is a proxy contract.
            The generated object will send transactions to `address`, but use the ABI
            and NatSpec of `as_proxy_for`. This field is only required when the
            block explorer API does not provide an implementation address.
        owner : Account, optional
            Contract owner. If set, transactions without a `from` field will be
            performed using this account.
        """
        address = _resolve_address(address)
        data = _fetch_from_explorer(address, "getsourcecode", silent)
        is_verified = bool(data["result"][0].get("SourceCode"))

        if is_verified:
            abi = json.loads(data["result"][0]["ABI"])
            name = data["result"][0]["ContractName"]
        else:
            # if the source is not available, try to fetch only the ABI
            try:
                data_abi = _fetch_from_explorer(address, "getabi", True)
            except ValueError as exc:
                _unverified_addresses.add(address)
                raise exc
            abi = json.loads(data_abi["result"].strip())
            name = "UnknownContractName"
            warnings.warn(
                f"{address}: Was able to fetch the ABI but not the source code. "
                "Some functionality will not be available.",
                BrownieCompilerWarning,
            )

        if as_proxy_for is None and data["result"][0].get("Implementation"):
            as_proxy_for = _resolve_address(
                data["result"][0]["Implementation"])

        # if this is a proxy, fetch information for the implementation contract
        if as_proxy_for is not None:
            implementation_contract = Contract.from_explorer(as_proxy_for)
            abi = implementation_contract._build["abi"]

        if not is_verified:
            return cls.from_abi(name, address, abi, owner)

        try:
            version = Version(
                data["result"][0]["CompilerVersion"].lstrip("v")).truncate()
        except Exception:
            version = Version("0.0.0")
        if version < Version("0.4.22") or (
                # special case for OSX because installing 0.4.x versions is problematic
                sys.platform == "darwin" and version < Version("0.5.0")
                and f"v{version}" not in solcx.get_installed_solc_versions()):
            if not silent:
                warnings.warn(
                    f"{address}: target compiler '{data['result'][0]['CompilerVersion']}' is "
                    "unsupported by Brownie. Some functionality will not be available.",
                    BrownieCompilerWarning,
                )
            return cls.from_abi(name, address, abi, owner)

        optimizer = {
            "enabled": bool(int(data["result"][0]["OptimizationUsed"])),
            "runs": int(data["result"][0]["Runs"]),
        }
        evm_version = data["result"][0].get("EVMVersion", "Default")
        if evm_version == "Default":
            evm_version = None

        if data["result"][0]["SourceCode"].startswith("{"):
            # source was verified using compiler standard JSON
            input_json = json.loads(data["result"][0]["SourceCode"][1:-1])
            sources = {
                k: v["content"]
                for k, v in input_json["sources"].items()
            }
            evm_version = input_json["settings"].get("evmVersion", evm_version)

            compiler.set_solc_version(str(version))
            input_json.update(
                compiler.generate_input_json(sources,
                                             optimizer=optimizer,
                                             evm_version=evm_version))
            output_json = compiler.compile_from_input_json(input_json)
            build_json = compiler.generate_build_json(input_json, output_json)
        else:
            # source was submitted as a single flattened file
            sources = {
                f"{name}-flattened.sol": data["result"][0]["SourceCode"]
            }
            build_json = compiler.compile_and_format(sources,
                                                     solc_version=str(version),
                                                     optimizer=optimizer,
                                                     evm_version=evm_version)

        build_json = build_json[name]
        if as_proxy_for is not None:
            build_json.update(
                abi=abi, natspec=implementation_contract._build.get("natspec"))

        if not _verify_deployed_code(address, build_json["deployedBytecode"],
                                     build_json["language"]):
            warnings.warn(
                f"{address}: Locally compiled and on-chain bytecode do not match!",
                BrownieCompilerWarning,
            )
            del build_json["pcMap"]

        self = cls.__new__(cls)
        _ContractBase.__init__(self, None, build_json, sources)  # type: ignore
        _DeployedContractBase.__init__(self, address, owner)
        _add_deployment(self)
        return self
예제 #5
0
def test_compile_input_json_raises():
    input_json = compiler.generate_input_json({"path": "potato"}, True, 200)
    with pytest.raises(CompilerError):
        compiler.compile_from_input_json(input_json)
예제 #6
0
def solc5json(solc5source):
    compiler.set_solc_version("0.5.7")
    input_json = compiler.generate_input_json({"path": solc5source}, True, 200)
    yield compiler.compile_from_input_json(input_json)
예제 #7
0
def test_compile_input_json_raises():
    input_json = compiler.generate_input_json({"path.vy": "potato"},
                                              language="Vyper")
    with pytest.raises(StructureException):
        compiler.compile_from_input_json(input_json)
예제 #8
0
def vyjson(vysource):
    input_json = compiler.generate_input_json({"path.vy": vysource},
                                              language="Vyper")
    yield compiler.compile_from_input_json(input_json)
예제 #9
0
def solc6json(solc6source):
    compiler.set_solc_version("0.6.2")
    input_json = compiler.generate_input_json({"path.sol": solc6source}, True,
                                              200)
    yield compiler.compile_from_input_json(input_json)
예제 #10
0
def test_compile_input_json_evm_translates(solc5source, original, translated):
    compiler.set_solc_version("0.5.7")
    input_json = compiler.generate_input_json({"path.sol": solc5source}, True,
                                              200, original)
    compiler.compile_from_input_json(input_json)
예제 #11
0
def solc4json(solc4source):
    compiler.set_solc_version("0.4.25")
    input_json = compiler.generate_input_json({'path': solc4source}, True, 200)
    yield compiler.compile_from_input_json(input_json)
예제 #12
0
def _solc_5_output_json():
    source = _solc_5_source()
    input_json = compiler.generate_input_json({'path': source}, True, 200)
    return compiler.compile_from_input_json(input_json)
예제 #13
0
def _solc_4_output_json():
    compiler.set_solc_version("0.4.25")
    source = _solc_4_source()
    input_json = compiler.generate_input_json({'path': source}, True, 200)
    return compiler.compile_from_input_json(input_json)
예제 #14
0
def test_compile_input_json_raises(vyper_version):
    compiler.vyper.set_vyper_version(vyper_version)
    input_json = compiler.generate_input_json({"path.vy": "potato"},
                                              language="Vyper")
    with pytest.raises(CompilerError):
        compiler.compile_from_input_json(input_json)
예제 #15
0
def vyjson(vysource):
    compiler.vyper.set_vyper_version("0.2.4")
    input_json = compiler.generate_input_json({"path.vy": vysource},
                                              language="Vyper")
    yield compiler.compile_from_input_json(input_json)