Module ethers_solc::resolver
source · Expand description
Resolution of the entire dependency graph for a project.
This module implements the core logic in taking all contracts of a project and creating a resolved graph with applied remappings for all source contracts.
Some constraints we’re working with when resolving contracts
- Each file can contain several source units and can have any number of imports/dependencies (using the term interchangeably). Each dependency can declare a version range that it is compatible with, solidity version pragma.
- A dependency can be imported from any directory,
see
Remappings
Finding all dependencies is fairly simple, we’re simply doing a DFS, starting the source contracts
Solc version auto-detection
Solving a constraint graph is an NP-hard problem. The algorithm for finding the “best” solution makes several assumptions and tries to find a version of “Solc” that is compatible with all source files.
The algorithm employed here is fairly simple, we simply do a DFS over all the source files and find the set of Solc versions that the file and all its imports are compatible with, and then we try to find a single Solc version that is compatible with all the files. This is effectively the intersection of all version sets.
We always try to activate the highest (installed) solc version first. Uninstalled solc is only used if this version is the only compatible version for a single file or in the intersection of all version sets.
This leads to finding the optimal version, if there is one. If there is no single Solc version that is compatible with all sources and their imports, then suddenly this becomes a very difficult problem, because what would be the “best” solution. In this case, just choose the latest (installed) Solc version and try to minimize the number of Solc versions used.
Performance
Note that this is a relatively performance-critical portion of the ethers-solc preprocessing. The data that needs to be processed is proportional to the size of the dependency graph, which can, depending on the project, often be quite large.
Note that, unlike the solidity compiler, we work with the filesystem, where we have to resolve remappings and follow relative paths. We’re also limiting the nodes in the graph to solidity files, since we’re only interested in their version pragma, which is defined on a per source file basis.