Consensys/scribble

`ParserError` file not found on truffle-compilation of scribble instrumented code

cd1m0 opened this issue · 0 comments

cd1m0 commented

If you have a truffle repo with

  1. invariant annotation on a contract X, which inherits from contract Y, where Y is defined in a package under node_modules/
  2. And you instrument and arm the code
  3. Try to run truffle compile

You will run into compilation failures like this one:

ParserError: Source "contracts/__scribble_ReentrancyUtils.sol" not found
 --> @openzeppelin/contracts/access/AccessControlEnumerable.sol:8:1:
  |
8 | import "./../../../../contracts/__scribble_ReentrancyUtils.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The issue is that our instrumentation needs to modify all base contracts, including the ones under node_modules/. As part of the modification, they need to inherit from the __scribble_ReentrancyUtils contract, which is usually placed at the root of the contracts/ directory. This adds an import from the node_modules/ directory back into the contracts/ directory.

In other development environments, to compile such contracts users need to specify a path remapping like @openzeppelin=node_modules/@openzeppelin. As a result, the solc compiler will preform the following steps when resolving the import declaration above:

  1. Append the relative import path to the current file directory path. In the above example we would append ./../../../../contracts/__scribble_ReentrancyUtils.sol to @openzeppelin/contracts/access/ to obtain
    @openzeppelin/contracts/access/./../../../../contracts/__scribble_ReentrancyUtils.sol
  2. Apply any path remappings. In the above example we would apply @openzeppelin=node_modules/@openzeppelin to @openzeppelin/contracts/access/./../../../../contracts/__scribble_ReentrancyUtils.sol to obtain
    node_modules/@openzeppelin/contracts/access/./../../../../contracts/__scribble_ReentrancyUtils.sol
  3. Normalize the path, collapsing any . and .. In the above example this would transform node_modules/@openzeppelin/contracts/access/./../../../../contracts/__scribble_ReentrancyUtils.sol into contracts/__scribble_ReentrancyUtils.sol
  4. Resolve the obtained path.

However in the case of truffle, it seems to be doing its own separate import path resolution, and building the complete standard json input to pass in to the compiler (around here). That doesn't seem to like our relative imports.

Steps to reproduce:

git clone git@github.com:cd1m0/scribble-truffle-remapping-bug.git
cd scribble-truffle-remapping-bug/
npm install
scribble contracts/Foo.sol --output-mode files --arm --path-remapping '@openzeppelin=node_modules/@openzeppelin' --compiler-version 0.8.11
truffle compile

You should see the following errors:

ParserError: Source "contracts/__scribble_ReentrancyUtils.sol" not found
 --> @openzeppelin/contracts/token/ERC20/ERC20.sol:8:1:
  |
8 | import "./../../../../../contracts/__scribble_ReentrancyUtils.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

,ParserError: Source "contracts/__scribble_ReentrancyUtils.sol" not found
 --> @openzeppelin/contracts/utils/Context.sol:5:1:
  |
5 | import "./../../../../contracts/__scribble_ReentrancyUtils.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Compilation failed. See above.