eth-brownie / brownie

A Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine.
https://eth-brownie.readthedocs.io
MIT License
2.63k stars 549 forks source link

Brownie crashes when compiling a library defined in a separate file using solc >= 0.7.2 #828

Closed cameel closed 3 years ago

cameel commented 3 years ago

Environment information

What was wrong?

A trivial project that just includes an empty contract and an empty library in separate files crashes brownie (KeyError: 'L').

This happens only when using solc >= 0.7.2.

To reproduce, run this code in the shell in an empty directory (assuming that Brownie is already installed):

brownie init

cat << EOF > contracts/C.sol
pragma solidity >=0.7.2;

import './L.sol';

contract C {}
EOF

cat << EOF > contracts/L.sol
pragma solidity >=0.7.2;

library L {}
EOF

brownie compile

Output:

Brownie v1.11.10 - Python development framework for Ethereum

Compiling contracts...
  Solc version: 0.7.4
  Optimizer: Enabled  Runs: 200
  EVM Version: Istanbul
Generating build data...
  File "brownie/_cli/__main__.py", line 64, in main
    importlib.import_module(f"brownie._cli.{cmd}").main()
  File "brownie/_cli/compile.py", line 50, in main
    proj = project.load()
  File "brownie/project/main.py", line 702, in load
    return Project(name, project_path)
  File "brownie/project/main.py", line 164, in __init__
    self.load()
  File "brownie/project/main.py", line 217, in load
    self._compile(changed, self._compiler_config, False)
  File "brownie/project/main.py", line 90, in _compile
    build_json = compiler.compile_and_format(
  File "brownie/project/compiler/__init__.py", line 146, in compile_and_format
    build_json.update(generate_build_json(input_json, output_json, compiler_data, silent))
  File "brownie/project/compiler/__init__.py", line 287, in generate_build_json
    source_nodes, statement_nodes, branch_nodes = solidity._get_nodes(output_json)
  File "brownie/project/compiler/solidity.py", line 545, in _get_nodes
    source_nodes = solcast.from_standard_output(output_json)
  File "solcast/main.py", line 33, in from_standard_output
    source_nodes = set_dependencies(source_nodes)
  File "solcast/dependencies.py", line 12, in set_dependencies
    symbol_map = get_symbol_map(source_nodes)
  File "solcast/dependencies.py", line 74, in get_symbol_map
    symbol_map.update((v[0], node[k]) for k, v in node.exportedSymbols.items())
  File "solcast/dependencies.py", line 74, in <genexpr>
    symbol_map.update((v[0], node[k]) for k, v in node.exportedSymbols.items())
  File "solcast/nodes.py", line 207, in __getitem__
    raise KeyError(key)
KeyError: 'L'

How can it be fixed?

I'm not sure but solc 0.7.2 introduced some AST changes that were not properly handled e.g. in Truffle (generatedSources, see https://github.com/trufflesuite/truffle/issues/3419, https://github.com/ethereum/solidity/issues/9980) and this might be a similar situation.

iamdefinitelyahuman commented 3 years ago

Indeed, this is a result of changes to the AST in v0.7.2. Thanks for the related issues, they will make it easier to fix this.